From b3fc64f455e128b29f9d4b33942bf3dc5f24b0c2 Mon Sep 17 00:00:00 2001 From: mimic Date: Fri, 13 Mar 2020 17:57:09 +0100 Subject: [PATCH] more context --- .../ediff/HierarchicalRegrouperForC.java | 23 +- .../serval/fixminer/ediff/TestInputCases.java | 50 +- .../serval/fixminer/ediff/TestRealCases.java | 114 +- src/main/resource/MF0012.local.app.properties | 5 +- .../prevFiles/prev_248-B-3757114-3757122.c | 21 + .../prevFiles/prev_31-B-14288247-14288278.c | 26 + .../prevFiles/prev_430-B-10625991-10626001.c | 43 + .../prevFiles/prev_494-A-10139010-10139025.c | 55 + .../prevFiles/prev_496-A-15303159-15303846.c | 24 + .../prevFiles/prev_509-B-11349359-11354327.c | 27 + .../prevFiles/prev_6-C-12776326-12776346.c | 67 + .../prevFiles/prev_60-A-510615-510619.c | 33 + .../revFiles/248-B-3757114-3757122.c | 21 + .../revFiles/31-B-14288247-14288278.c | 27 + .../revFiles/430-B-10625991-10626001.c | 44 + .../revFiles/494-A-10139010-10139025.c | 55 + .../revFiles/496-A-15303159-15303846.c | 25 + .../revFiles/509-B-11349359-11354327.c | 27 + .../revFiles/6-C-12776326-12776346.c | 70 + .../codeflaws/revFiles/60-A-510615-510619.c | 33 + .../prev_6a619f_46ab6d_Modules#posixmodule.c | 3493 ++++++++++++++++ .../prev_df0d00_1254d7_Python#ceval.c | 2740 +++++++++++++ .../prev_f62026_71eb864_Python#ceval.c | 2880 ++++++++++++++ .../6a619f_46ab6d_Modules#posixmodule.c | 3503 +++++++++++++++++ .../revFiles/df0d00_1254d7_Python#ceval.c | 2740 +++++++++++++ .../revFiles/f62026_71eb864_Python#ceval.c | 2888 ++++++++++++++ .../gzip/prevFiles/prev_051ed8_8b83dc_gzip.c | 2165 ++++++++++ .../gzip/revFiles/051ed8_8b83dc_gzip.c | 2165 ++++++++++ .../prevFiles/prev_e76cf8_39753f_Zend#zend.c | 1472 +++++++ .../revFiles/e76cf8_39753f_Zend#zend.c | 1472 +++++++ 30 files changed, 26286 insertions(+), 22 deletions(-) create mode 100644 src/main/resource/testFiles/codeflaws/prevFiles/prev_248-B-3757114-3757122.c create mode 100644 src/main/resource/testFiles/codeflaws/prevFiles/prev_31-B-14288247-14288278.c create mode 100644 src/main/resource/testFiles/codeflaws/prevFiles/prev_430-B-10625991-10626001.c create mode 100644 src/main/resource/testFiles/codeflaws/prevFiles/prev_494-A-10139010-10139025.c create mode 100644 src/main/resource/testFiles/codeflaws/prevFiles/prev_496-A-15303159-15303846.c create mode 100644 src/main/resource/testFiles/codeflaws/prevFiles/prev_509-B-11349359-11354327.c create mode 100644 src/main/resource/testFiles/codeflaws/prevFiles/prev_6-C-12776326-12776346.c create mode 100644 src/main/resource/testFiles/codeflaws/prevFiles/prev_60-A-510615-510619.c create mode 100644 src/main/resource/testFiles/codeflaws/revFiles/248-B-3757114-3757122.c create mode 100644 src/main/resource/testFiles/codeflaws/revFiles/31-B-14288247-14288278.c create mode 100644 src/main/resource/testFiles/codeflaws/revFiles/430-B-10625991-10626001.c create mode 100644 src/main/resource/testFiles/codeflaws/revFiles/494-A-10139010-10139025.c create mode 100644 src/main/resource/testFiles/codeflaws/revFiles/496-A-15303159-15303846.c create mode 100644 src/main/resource/testFiles/codeflaws/revFiles/509-B-11349359-11354327.c create mode 100644 src/main/resource/testFiles/codeflaws/revFiles/6-C-12776326-12776346.c create mode 100644 src/main/resource/testFiles/codeflaws/revFiles/60-A-510615-510619.c create mode 100644 src/main/resource/testFiles/cpython/prevFiles/prev_6a619f_46ab6d_Modules#posixmodule.c create mode 100644 src/main/resource/testFiles/cpython/prevFiles/prev_df0d00_1254d7_Python#ceval.c create mode 100644 src/main/resource/testFiles/cpython/prevFiles/prev_f62026_71eb864_Python#ceval.c create mode 100644 src/main/resource/testFiles/cpython/revFiles/6a619f_46ab6d_Modules#posixmodule.c create mode 100644 src/main/resource/testFiles/cpython/revFiles/df0d00_1254d7_Python#ceval.c create mode 100644 src/main/resource/testFiles/cpython/revFiles/f62026_71eb864_Python#ceval.c create mode 100644 src/main/resource/testFiles/gzip/prevFiles/prev_051ed8_8b83dc_gzip.c create mode 100644 src/main/resource/testFiles/gzip/revFiles/051ed8_8b83dc_gzip.c create mode 100644 src/main/resource/testFiles/php-src/prevFiles/prev_e76cf8_39753f_Zend#zend.c create mode 100644 src/main/resource/testFiles/php-src/revFiles/e76cf8_39753f_Zend#zend.c diff --git a/src/main/java/edu/lu/uni/serval/fixminer/ediff/HierarchicalRegrouperForC.java b/src/main/java/edu/lu/uni/serval/fixminer/ediff/HierarchicalRegrouperForC.java index 47bfc1a..be0e9c3 100644 --- a/src/main/java/edu/lu/uni/serval/fixminer/ediff/HierarchicalRegrouperForC.java +++ b/src/main/java/edu/lu/uni/serval/fixminer/ediff/HierarchicalRegrouperForC.java @@ -106,9 +106,9 @@ public class HierarchicalRegrouperForC { } private HierarchicalActionSet purifyActionSet(HierarchicalActionSet actionSet){ HierarchicalActionSet hierarchicalActionSet = removeBlocks(actionSet); - hierarchicalActionSet = removeIFthenBlocks(hierarchicalActionSet); - hierarchicalActionSet = removeParentForSingle(hierarchicalActionSet); - hierarchicalActionSet = removeParentNode(hierarchicalActionSet); +// hierarchicalActionSet = removeIFthenBlocks(hierarchicalActionSet); +// hierarchicalActionSet = removeParentForSingle(hierarchicalActionSet); +// hierarchicalActionSet = removeParentNode(hierarchicalActionSet); return hierarchicalActionSet; // return actionSet; } @@ -154,6 +154,7 @@ public class HierarchicalRegrouperForC { Predicate predicate = x->NodeMap_new.getKeysByValue(NodeMap_new.StatementMap,x.getAstNodeType()).size() == 1 ; Predicate predicate1 = x->!x.getAstNodeType().equals("block"); Predicate predicate2 = x->!x.getAstNodeType().equals("then"); +// Predicate predicate3 = p->p.getAction().getName().equals(subActions.get(0).getAction().getName())); private HierarchicalActionSet removeBlocks(HierarchicalActionSet actionSet){ List subActions = actionSet.getSubActions(); @@ -162,20 +163,28 @@ public class HierarchicalRegrouperForC { Action action = actionSet.getAction(); if (subActions.size() == 1){ HierarchicalActionSet subaction = subActions.get(0); - if(!postOrder(subaction).stream().anyMatch(predicate.and(predicate1.and(predicate2)))){ +// if(!postOrder(subaction).stream().anyMatch(predicate.and(predicate1.and(predicate2)))){ +// return actionSet; +// } + List collect = postOrder(subaction).stream().filter(predicate.and(predicate1.and(predicate2))).collect(Collectors.toList()); + if(collect.size() == 0){ + return actionSet; + } + boolean b = collect.stream().anyMatch(p -> p.getAction().getName().equals(subActions.get(0).getAction().getName())); + if(!b){ return actionSet; } Action action1 = subaction.getAction(); //else,then,block if(action.getClass().equals(action1.getClass()) && action.getName().equals("UPD")) { - List keysByValue = NodeMap_new.getKeysByValue(NodeMap_new.StatementMap, subaction.getAstNodeType()); - if (keysByValue != null && keysByValue.size() == 1) { +// List keysByValue = NodeMap_new.getKeysByValue(NodeMap_new.StatementMap, subaction.getAstNodeType()); +// if (keysByValue != null && keysByValue.size() == 1) { subaction.setParent(null); return removeBlocks(subaction); - } +// } // if(areRelatedActions(action,action1)) { // if (subaction.getAstNodeType().equals("block")) {//|| subaction.getAstNodeType().equals("then") || subaction.getAstNodeType().equals("else")){ // List subSubActions = subaction.getSubActions(); diff --git a/src/main/java/edu/lu/uni/serval/fixminer/ediff/TestInputCases.java b/src/main/java/edu/lu/uni/serval/fixminer/ediff/TestInputCases.java index b4cb466..ffe942b 100644 --- a/src/main/java/edu/lu/uni/serval/fixminer/ediff/TestInputCases.java +++ b/src/main/java/edu/lu/uni/serval/fixminer/ediff/TestInputCases.java @@ -601,15 +601,16 @@ public class TestInputCases { "------UPD call@@PyString_FromString \"\" @TO@ PySequence_GetSlice pattern 0 0 @AT@ 52073 @LENGTH@ 22\n" + "---------UPD name@@PyString_FromString @TO@ PySequence_GetSlice @AT@ 52073 @LENGTH@ 19\n" + "---------UPD argument_list@@\"\" @TO@ pattern 0 0 @AT@ 52092 @LENGTH@ 2\n" + - "------------INS argument@@pattern @TO@ argument_list@@\"\" @AT@ 51091 @LENGTH@ 7\n" + - "---------------INS expr@@pattern @TO@ argument@@pattern @AT@ 51091 @LENGTH@ 7\n" + - "------------------INS name@@pattern @TO@ expr@@pattern @AT@ 51091 @LENGTH@ 7\n" + + "------------INS argument@@0 @TO@ argument_list@@\"\" @AT@ 51100 @LENGTH@ 1\n" + + "---------------INS expr@@0 @TO@ argument@@0 @AT@ 51100 @LENGTH@ 1\n" + + "------------------INS literal:number@@0 @TO@ expr@@0 @AT@ 51100 @LENGTH@ 1\n" + "------------INS argument@@0 @TO@ argument_list@@\"\" @AT@ 51103 @LENGTH@ 1\n" + "---------------INS expr@@0 @TO@ argument@@0 @AT@ 51103 @LENGTH@ 1\n" + "------------------INS literal:number@@0 @TO@ expr@@0 @AT@ 51103 @LENGTH@ 1\n" + - "------------UPD argument@@\"\" @TO@ 0 @AT@ 52093 @LENGTH@ 2\n" + - "---------------UPD expr@@\"\" @TO@ 0 @AT@ 52093 @LENGTH@ 2\n" + - "------------------UPD literal:string@@\"\" @TO@ 0 @AT@ 52093 @LENGTH@ 2\n"); + "------------UPD argument@@\"\" @TO@ pattern @AT@ 52093 @LENGTH@ 2\n" + + "---------------UPD expr@@\"\" @TO@ pattern @AT@ 52093 @LENGTH@ 2\n" + + "------------------INS name@@pattern @TO@ expr@@\"\" @AT@ 51091 @LENGTH@ 7\n" + + "------------------DEL literal:string@@\"\" @AT@ 52093 @LENGTH@ 2\n"); } @Test public void test_cpython_03897e_8fcc8e() throws IOException { @@ -865,9 +866,9 @@ public class TestInputCases { List hierarchicalActionSets = getHierarchicalActionSets("cpython_719f5f_dcc6ef_Objects#intobject.c");//wrong Assert.assertEquals(hierarchicalActionSets.size(),1); - Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"UPD block@@long d m if i_divmod x y & d & m < 0 return NULL newintobject m @TO@ long d m if i_divmod x y & d & m < 0 return NULL return newintobject m @AT@ 4993 @LENGTH@ 63\n" + + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"UPD block@@long d long m if i_divmod x y & d & m < 0 return NULL newintobject m @TO@ long d long m if i_divmod x y & d & m < 0 return NULL return newintobject m @AT@ 4993 @LENGTH@ 68\n" + "---DEL expr_stmt@@newintobject m @AT@ 5056 @LENGTH@ 14\n" + - "---INS return@@return newintobject m @TO@ block@@long d m if i_divmod x y & d & m < 0 return NULL newintobject m @AT@ 5112 @LENGTH@ 21\n" + + "---INS return@@return newintobject m @TO@ block@@long d long m if i_divmod x y & d & m < 0 return NULL newintobject m @AT@ 5112 @LENGTH@ 21\n" + "------MOV expr@@newintobject m @TO@ return@@return newintobject m @AT@ 5056 @LENGTH@ 14\n"); } @Test @@ -1017,7 +1018,7 @@ public class TestInputCases { public void test_php_src_a10e77_634012() throws IOException { List hierarchicalActionSets = getHierarchicalActionSets("php-src_a10e77_634012_ext#phar#tar.c");// Assert.assertEquals(hierarchicalActionSets.size(),1); - Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"INS if@@if entry . filename_len == UINT_MAX if error spprintf error 4096 \"phar error: \\\"%s\\\" is a corrupted tar file (invalid entry size)\" fname php_stream_close fp phar_destroy_phar_data myphar TSRMLS_CC return FAILURE @TO@ block@@last_was_longlink = 1 entry . filename_len = entry . uncompressed_filesize entry . filename = pemalloc entry . filename_len + 1 myphar -> is_persistent read = php_stream_read fp entry . filename entry . filename_len if read != entry . filename_len efree entry . filename if error spprintf error 4096 \"phar error: \\\"%s\\\" is a corrupted tar file (truncated)\" fname php_stream_close fp phar_destroy_phar_data myphar TSRMLS_CC return FAILURE entry . filename ][entry . filename_len = '\\0' size = ( ( size + 511 ) & ~ 511 ) - size php_stream_seek fp size SEEK_CUR if ( uint ) php_stream_tell fp > totalsize efree entry . filename if error spprintf error 4096 \"phar error: \\\"%s\\\" is a corrupted tar file (truncated)\" fname php_stream_close fp phar_destroy_phar_data myphar TSRMLS_CC return FAILURE read = php_stream_read fp buf buf if read != buf efree entry . filename if error spprintf error 4096 \"phar error: \\\"%s\\\" is a corrupted tar file (truncated)\" fname php_stream_close fp phar_destroy_phar_data myphar TSRMLS_CC return FAILURE continue; @AT@ 11511 @LENGTH@ 211\n" + + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"INS if@@if entry . filename_len == UINT_MAX if error spprintf error 4096 \"phar error: \\\"%s\\\" is a corrupted tar file (invalid entry size)\" fname php_stream_close fp phar_destroy_phar_data myphar TSRMLS_CC return FAILURE @TO@ block@@last_was_longlink = 1 entry . filename_len = entry . uncompressed_filesize entry . filename = pemalloc entry . filename_len + 1 myphar -> is_persistent read = php_stream_read fp entry . filename entry . filename_len if read != entry . filename_len efree entry . filename if error spprintf error 4096 \"phar error: \\\"%s\\\" is a corrupted tar file (truncated)\" fname php_stream_close fp phar_destroy_phar_data myphar TSRMLS_CC return FAILURE entry . filename ][entry . filename_len = '\\0' size = ( ( size + 511 ) & ~ 511 ) - size php_stream_seek fp size SEEK_CUR if ( uint ) php_stream_tell fp > totalsize efree entry . filename if error spprintf error 4096 \"phar error: \\\"%s\\\" is a corrupted tar file (truncated)\" fname php_stream_close fp phar_destroy_phar_data myphar TSRMLS_CC return FAILURE read = php_stream_read fp buf sizeof buf if read != sizeof buf efree entry . filename if error spprintf error 4096 \"phar error: \\\"%s\\\" is a corrupted tar file (truncated)\" fname php_stream_close fp phar_destroy_phar_data myphar TSRMLS_CC return FAILURE continue; @AT@ 11511 @LENGTH@ 211\n" + "---INS condition@@entry . filename_len == UINT_MAX @TO@ if@@if entry . filename_len == UINT_MAX if error spprintf error 4096 \"phar error: \\\"%s\\\" is a corrupted tar file (invalid entry size)\" fname php_stream_close fp phar_destroy_phar_data myphar TSRMLS_CC return FAILURE @AT@ 11511 @LENGTH@ 32\n" + "------INS expr@@entry . filename_len == UINT_MAX @TO@ condition@@entry . filename_len == UINT_MAX @AT@ 11512 @LENGTH@ 32\n" + "---------INS name@@entry . filename_len @TO@ expr@@entry . filename_len == UINT_MAX @AT@ 11512 @LENGTH@ 20\n" + @@ -1183,7 +1184,36 @@ public class TestInputCases { } + @Test + public void test_php_src_e76cf8_39753f() throws IOException { + List hierarchicalActionSets = getHierarchicalActionSets("php-src_e76cf8_39753f_Zend#zend.c"); + Assert.assertEquals(hierarchicalActionSets.size(),1); + } + @Test + public void test_cpython_f62026_71eb864() throws IOException { + + List hierarchicalActionSets = getHierarchicalActionSets("cpython_f62026_71eb864_Python#ceval.c"); + Assert.assertEquals(hierarchicalActionSets.size(),1); + } + @Test + public void test_cpython_df0d00_1254d7() throws IOException { + + List hierarchicalActionSets = getHierarchicalActionSets("cpython_df0d00_1254d7_Python#ceval.c"); + Assert.assertEquals(hierarchicalActionSets.size(),1); + } + @Test + public void test_cpython_6a619f_46ab6d() throws IOException { + + List hierarchicalActionSets = getHierarchicalActionSets("cpython_6a619f_46ab6d_Modules#posixmodule.c"); + Assert.assertEquals(hierarchicalActionSets.size(),1); + } + @Test + public void test_gzip_051ed8_8b83dc() throws IOException { + //null pointer + List hierarchicalActionSets = getHierarchicalActionSets("gzip_051ed8_8b83dc_gzip.c"); + Assert.assertEquals(hierarchicalActionSets.size(),1); + } public List getHierarchicalActionSets(String s) throws IOException { Properties appProps = new Properties(); @@ -1200,7 +1230,7 @@ public class TestInputCases { EDiffHunkParser parser = new EDiffHunkParser(); - +// srcMLPath = "/usr/local/bin/srcml"; List hierarchicalActionSets = parser.parseChangedSourceCodeWithGumTree2(prevFile, revFile, srcMLPath,false); return hierarchicalActionSets; }catch (NullPointerException n){ diff --git a/src/main/java/edu/lu/uni/serval/fixminer/ediff/TestRealCases.java b/src/main/java/edu/lu/uni/serval/fixminer/ediff/TestRealCases.java index f366336..f54c60a 100644 --- a/src/main/java/edu/lu/uni/serval/fixminer/ediff/TestRealCases.java +++ b/src/main/java/edu/lu/uni/serval/fixminer/ediff/TestRealCases.java @@ -468,8 +468,7 @@ public class TestRealCases { List hierarchicalActionSets = getHierarchicalActionSets("31-B-136044-136045.c"); Assert.assertEquals(hierarchicalActionSets.size(),1); - Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"MOV if@@if flag puts ans + 1 else printf \"No solution\\n\" @TO@ block@@long i l flag 0 tot 0 gets str + 1 l = strlen str + 1 if str ][1 == '@' || str ][l == '@' end for i = 1 i <= l - 2 i ++ if str ][i == '@' && ( str ][i + 1 == '@' || str ][i + 2 == '@' ) end for i = 1 i <= l i ++ if flag && str ][i + 1 == '@' ans ][++ tot = ',' if str ][i == '@' flag = 1 ans ][++ tot = str ][i if flag puts ans + 1 else printf \"No solution\\n\" end return 0 @AT@ 937 @LENGTH@ 48\n"); - + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"MOV if@@if flag puts ans + 1 else printf \"No solution\\n\" @TO@ block@@long i long l long flag 0 long tot 0 gets str + 1 l = strlen str + 1 if str ][1 == '@' || str ][l == '@' end for i = 1 i <= l - 2 i ++ if str ][i == '@' && ( str ][i + 1 == '@' || str ][i + 2 == '@' ) end for i = 1 i <= l i ++ if flag && str ][i + 1 == '@' ans ][++ tot = ',' if str ][i == '@' flag = 1 ans ][++ tot = str ][i if flag puts ans + 1 else printf \"No solution\\n\" end return 0 @AT@ 937 @LENGTH@ 48\n"); } @Test @@ -754,6 +753,117 @@ public class TestRealCases { "------------------------------INS name@@[rear @TO@ expr@@[rear @AT@ 1850 @LENGTH@ 5\n" + "------------UPD operator@@++ @TO@ += @AT@ 1874 @LENGTH@ 2\n"); } + + @Test + public void test_496_A_15303159_15303846() throws IOException { + + List hierarchicalActionSets = getHierarchicalActionSets("496-A-15303159-15303846.c"); + Assert.assertEquals(hierarchicalActionSets.size(), 1); + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"INS expr_stmt@@max = 0 @TO@ block@@for j = 0 j < n - 1 j ++ if i == j + 1 && max < a ][j + 2 - a ][j max = a ][j + 2 - a ][j elseif if max < a ][j + 1 - a ][j max = a ][j + 1 - a ][j b ][i = max @AT@ 155 @LENGTH@ 7\n" + + "---INS expr@@max = 0 @TO@ expr_stmt@@max = 0 @AT@ 155 @LENGTH@ 7\n" + + "------INS name@@max @TO@ expr@@max = 0 @AT@ 155 @LENGTH@ 3\n" + + "------INS operator@@= @TO@ expr@@max = 0 @AT@ 158 @LENGTH@ 1\n" + + "------INS literal:number@@0 @TO@ expr@@max = 0 @AT@ 159 @LENGTH@ 1\n"); + } + + @Test + public void test_430_B_10625991_10626001() throws IOException { + + List hierarchicalActionSets = getHierarchicalActionSets("430-B-10625991-10626001.c"); + Assert.assertEquals(hierarchicalActionSets.size(), 1); + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"INS else@@else break; @TO@ if@@if A ][start == A ][end && ( start && A ][start - 1 == A ][end ) && ( end != n - 1 && A ][start == A ][end + 1 ) count2 = 4 , start -= 2 , end += 2 elseif if ( A ][start == A ][end ) && ( start && A ][start - 1 == A ][end ) count2 = 3 , start -= 2 , end += 1 elseif if ( A ][start == A ][end ) && ( end != n - 1 && A ][start == A ][end + 1 ) count2 = 3 , start -= 1 , end += 2 @AT@ 803 @LENGTH@ 11\n" + + "---INS block@@break; @TO@ else@@else break; @AT@ 803 @LENGTH@ 6\n" + + "------INS break@@break; @TO@ block@@break; @AT@ 803 @LENGTH@ 6\n"); + } + @Test + public void test_60_A_510615_510619() throws IOException { + //wrong + List hierarchicalActionSets = getHierarchicalActionSets("60-A-510615-510619.c"); + Assert.assertEquals(hierarchicalActionSets.size(), 1); + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"INS else@@else break; @TO@ if@@if A ][start == A ][end && ( start && A ][start - 1 == A ][end ) && ( end != n - 1 && A ][start == A ][end + 1 ) count2 = 4 , start -= 2 , end += 2 elseif if ( A ][start == A ][end ) && ( start && A ][start - 1 == A ][end ) count2 = 3 , start -= 2 , end += 1 elseif if ( A ][start == A ][end ) && ( end != n - 1 && A ][start == A ][end + 1 ) count2 = 3 , start -= 1 , end += 2 @AT@ 803 @LENGTH@ 11\n" + + "---INS block@@break; @TO@ else@@else break; @AT@ 803 @LENGTH@ 6\n" + + "------INS break@@break; @TO@ block@@break; @AT@ 803 @LENGTH@ 6\n"); + } + @Test + public void test_509_B_11349359_11354327() throws IOException { + //wrong// + List hierarchicalActionSets = getHierarchicalActionSets("509-B-11349359-11354327.c"); + Assert.assertEquals(hierarchicalActionSets.size(), 1); + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"UPD ternary@@j < min 1 else j - min + 1 @TO@ j <= min 1 else j - min @AT@ 368 @LENGTH@ 26\n" + + "---UPD condition@@j < min @TO@ j <= min @AT@ 368 @LENGTH@ 7\n" + + "------UPD expr@@j < min @TO@ j <= min @AT@ 368 @LENGTH@ 7\n" + + "---------UPD operator@@< @TO@ <= @AT@ 369 @LENGTH@ 1\n" + + "---UPD else@@else j - min + 1 @TO@ else j - min @AT@ 380 @LENGTH@ 16\n" + + "------UPD expr@@j - min + 1 @TO@ j - min @AT@ 380 @LENGTH@ 11\n" + + "---------DEL operator@@+ @AT@ 385 @LENGTH@ 1\n" + + "---------DEL literal:number@@1 @AT@ 386 @LENGTH@ 1\n"); + } + @Test + public void test_6_C_12776326_12776346() throws IOException { + //wrong// + List hierarchicalActionSets = getHierarchicalActionSets("6-C-12776326-12776346.c"); + Assert.assertEquals(hierarchicalActionSets.size(), 1); + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"UPD if@@if n == 1 printf \"1 0\\n\" @TO@ if n == 1 printf \"1 0\\n\" return 0 @AT@ 83 @LENGTH@ 24\n" + + "---UPD then@@printf \"1 0\\n\" @TO@ printf \"1 0\\n\" return 0 @AT@ 94 @LENGTH@ 14\n" + + "------UPD block@@printf \"1 0\\n\" @TO@ printf \"1 0\\n\" return 0 @AT@ 94 @LENGTH@ 14\n" + + "---------MOV return@@return 0 @TO@ block@@printf \"1 0\\n\" @AT@ 111 @LENGTH@ 8\n"); + } + + @Test + public void test_494_A_10139010_10139025() throws IOException { + + List hierarchicalActionSets = getHierarchicalActionSets("494-A-10139010-10139025.c"); + Assert.assertEquals(hierarchicalActionSets.size(), 1); + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"UPD if@@if sum == 0 && h > 0 flag = 0 @TO@ if ( sum == 0 && h > 0 ) || sum - h + 1 <= 0 flag = 0 @AT@ 298 @LENGTH@ 29\n" + + "---UPD condition@@sum == 0 && h > 0 @TO@ ( sum == 0 && h > 0 ) || sum - h + 1 <= 0 @AT@ 298 @LENGTH@ 17\n" + + "------UPD expr@@sum == 0 && h > 0 @TO@ ( sum == 0 && h > 0 ) || sum - h + 1 <= 0 @AT@ 299 @LENGTH@ 17\n" + + "---------INS operator@@( @TO@ expr@@sum == 0 && h > 0 @AT@ 299 @LENGTH@ 1\n" + + "---------INS operator@@) @TO@ expr@@sum == 0 && h > 0 @AT@ 313 @LENGTH@ 1\n" + + "---------INS operator@@|| @TO@ expr@@sum == 0 && h > 0 @AT@ 315 @LENGTH@ 2\n" + + "---------INS name@@sum @TO@ expr@@sum == 0 && h > 0 @AT@ 318 @LENGTH@ 3\n" + + "---------INS operator@@- @TO@ expr@@sum == 0 && h > 0 @AT@ 321 @LENGTH@ 1\n" + + "---------INS name@@h @TO@ expr@@sum == 0 && h > 0 @AT@ 322 @LENGTH@ 1\n" + + "---------INS operator@@+ @TO@ expr@@sum == 0 && h > 0 @AT@ 323 @LENGTH@ 1\n" + + "---------INS literal:number@@1 @TO@ expr@@sum == 0 && h > 0 @AT@ 324 @LENGTH@ 1\n" + + "---------INS operator@@<= @TO@ expr@@sum == 0 && h > 0 @AT@ 325 @LENGTH@ 2\n" + + "---------INS literal:number@@0 @TO@ expr@@sum == 0 && h > 0 @AT@ 327 @LENGTH@ 1\n"); + } + + @Test + public void test_248_B_3757114_3757122() throws IOException { + + List hierarchicalActionSets = getHierarchicalActionSets("248-B-3757114-3757122.c"); + Assert.assertEquals(hierarchicalActionSets.size(), 1); + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"UPD expr_stmt@@printf \"%3d\\n\" suf ][n % P @TO@ printf \"%.*d\\n\" 3 suf ][n % P @AT@ 334 @LENGTH@ 26\n" + + "---UPD expr@@printf \"%3d\\n\" suf ][n % P @TO@ printf \"%.*d\\n\" 3 suf ][n % P @AT@ 334 @LENGTH@ 26\n" + + "------UPD call@@printf \"%3d\\n\" suf ][n % P @TO@ printf \"%.*d\\n\" 3 suf ][n % P @AT@ 334 @LENGTH@ 26\n" + + "---------UPD argument_list@@\"%3d\\n\" suf ][n % P @TO@ \"%.*d\\n\" 3 suf ][n % P @AT@ 341 @LENGTH@ 19\n" + + "------------UPD argument@@\"%3d\\n\" @TO@ \"%.*d\\n\" @AT@ 342 @LENGTH@ 7\n" + + "---------------UPD expr@@\"%3d\\n\" @TO@ \"%.*d\\n\" @AT@ 342 @LENGTH@ 7\n" + + "------------------UPD literal:string@@\"%3d\\n\" @TO@ \"%.*d\\n\" @AT@ 342 @LENGTH@ 7\n" + + "------------INS argument@@3 @TO@ argument_list@@\"%3d\\n\" suf ][n % P @AT@ 352 @LENGTH@ 1\n" + + "---------------INS expr@@3 @TO@ argument@@3 @AT@ 352 @LENGTH@ 1\n" + + "------------------INS literal:number@@3 @TO@ expr@@3 @AT@ 352 @LENGTH@ 1\n"); + } + + //codeflaws_31-B-14288247-14288278.c + @Test + public void test_31_B_14288247_14288278() throws IOException { + + List hierarchicalActionSets = getHierarchicalActionSets("31-B-14288247-14288278.c"); + Assert.assertEquals(hierarchicalActionSets.size(), 1); + Assert.assertEquals(hierarchicalActionSets.get(0).toString(),"UPD expr_stmt@@printf \"%3d\\n\" suf ][n % P @TO@ printf \"%.*d\\n\" 3 suf ][n % P @AT@ 334 @LENGTH@ 26\n" + + "---UPD expr@@printf \"%3d\\n\" suf ][n % P @TO@ printf \"%.*d\\n\" 3 suf ][n % P @AT@ 334 @LENGTH@ 26\n" + + "------UPD call@@printf \"%3d\\n\" suf ][n % P @TO@ printf \"%.*d\\n\" 3 suf ][n % P @AT@ 334 @LENGTH@ 26\n" + + "---------UPD argument_list@@\"%3d\\n\" suf ][n % P @TO@ \"%.*d\\n\" 3 suf ][n % P @AT@ 341 @LENGTH@ 19\n" + + "------------UPD argument@@\"%3d\\n\" @TO@ \"%.*d\\n\" @AT@ 342 @LENGTH@ 7\n" + + "---------------UPD expr@@\"%3d\\n\" @TO@ \"%.*d\\n\" @AT@ 342 @LENGTH@ 7\n" + + "------------------UPD literal:string@@\"%3d\\n\" @TO@ \"%.*d\\n\" @AT@ 342 @LENGTH@ 7\n" + + "------------INS argument@@3 @TO@ argument_list@@\"%3d\\n\" suf ][n % P @AT@ 352 @LENGTH@ 1\n" + + "---------------INS expr@@3 @TO@ argument@@3 @AT@ 352 @LENGTH@ 1\n" + + "------------------INS literal:number@@3 @TO@ expr@@3 @AT@ 352 @LENGTH@ 1\n"); + } + public List getHierarchicalActionSets(String s) throws IOException { Properties appProps = new Properties(); appProps.load(new FileInputStream("src/main/resource/app.properties")); diff --git a/src/main/resource/MF0012.local.app.properties b/src/main/resource/MF0012.local.app.properties index b0dcf48..6b90f36 100644 --- a/src/main/resource/MF0012.local.app.properties +++ b/src/main/resource/MF0012.local.app.properties @@ -1,11 +1,10 @@ portDumps = 6399 numOfWorkers = 14 -hunkLimit = 10 +hunkLimit = 1 patchSize = 50 -#projectList = libtiff,php-src,cpython,wireshark,gzip,gmp,lighttpd1.4,lighttpd2 -projectList = codeflaws +projectList = libtiff,php-src,cpython,wireshark,gzip,gmp,lighttpd1.4,lighttpd2 #inputPath = /Users/anilkoyuncu/projects/gumInputLinux #inputPath = /Users/anil.koyuncu/projects/fixminer/fixminer-data/gumInputLinux diff --git a/src/main/resource/testFiles/codeflaws/prevFiles/prev_248-B-3757114-3757122.c b/src/main/resource/testFiles/codeflaws/prevFiles/prev_248-B-3757114-3757122.c new file mode 100644 index 0000000..568cb08 --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/prevFiles/prev_248-B-3757114-3757122.c @@ -0,0 +1,21 @@ +#include +#include + +int main(int argc, char *argv[]) { + int n, suf[] = {170,20,200,110,50,80}, P = sizeof suf / sizeof *suf; + scanf ("%d", &n); + + if (n < 3) + printf ("-1\n"); + else if (n == 3) + printf ("210\n"); + else { + int i; + printf ("1"); + for (i = 0; i < n-4; ++i) + printf ("0"); + printf ("%3d\n", suf[n % P]); + } + exit (EXIT_SUCCESS); +return 0; +} diff --git a/src/main/resource/testFiles/codeflaws/prevFiles/prev_31-B-14288247-14288278.c b/src/main/resource/testFiles/codeflaws/prevFiles/prev_31-B-14288247-14288278.c new file mode 100644 index 0000000..cea14c0 --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/prevFiles/prev_31-B-14288247-14288278.c @@ -0,0 +1,26 @@ +#include + +int main(int argc, char *argv[]) { + char *p,*q,s[201]; + scanf("%s\n",s); + int ms=0; + for (p=s,q=p-2;*p;p++) { + if (*p=='@') + if (p-q<3) break; + else q=p; + ms=1; + } + int first=1; + if (*p||*(p-1)=='@'||!ms) printf("No solution\n"); + else { + for (p=s+1,q=s;*p;p++,q++) { + if (*p=='@') { + if (!first) printf(","); + first=0; + } + printf("%c",*q); + } + printf("%s\n",q); + } + return 0; +} diff --git a/src/main/resource/testFiles/codeflaws/prevFiles/prev_430-B-10625991-10626001.c b/src/main/resource/testFiles/codeflaws/prevFiles/prev_430-B-10625991-10626001.c new file mode 100644 index 0000000..df76c2c --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/prevFiles/prev_430-B-10625991-10626001.c @@ -0,0 +1,43 @@ +#include +int main(int argc, char *argv[]) +{ + int n,k,x,i,max=0,start,end; + scanf("%d%d%d",&n,&k,&x); + int A[n],consecutive[n-1],count=0,count2=0,temp,temp2,tempcount; + for(i=0;i=3) + tempcount=tempcount+count2; + + } + + if(tempcount>max) + max=tempcount; + } + printf("%d\n",max ); + return 0; +} \ No newline at end of file diff --git a/src/main/resource/testFiles/codeflaws/prevFiles/prev_494-A-10139010-10139025.c b/src/main/resource/testFiles/codeflaws/prevFiles/prev_494-A-10139010-10139025.c new file mode 100644 index 0000000..fe12a98 --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/prevFiles/prev_494-A-10139010-10139025.c @@ -0,0 +1,55 @@ +#include +#include +int main(int argc, char *argv[]){ + int flag,sum,max,sum1,i,j,k,l,n,m,h; + char c[100000]; + scanf("%s",c); + n = strlen(c); + h=0; + flag=1; + for(i=0;i0) + flag=0; + sum1=0; + if(flag==0) + printf("-1\n"); + else{ + for(i=0;i +int main(int argc, char *argv[]) +{ +int n,a[200],i,max=0,j,b[100]; +scanf("%d",&n); +for(i=0;ib[i]) +max=b[i]; +printf("%d",max); +return 0; +} diff --git a/src/main/resource/testFiles/codeflaws/prevFiles/prev_509-B-11349359-11354327.c b/src/main/resource/testFiles/codeflaws/prevFiles/prev_509-B-11349359-11354327.c new file mode 100644 index 0000000..20372b6 --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/prevFiles/prev_509-B-11349359-11354327.c @@ -0,0 +1,27 @@ +#include +int arr[52000],i,j,n,m,max=-31231212,min=1123132; +int main(int argc, char *argv[]){ + scanf("%d %d",&n,&m); + for(i=1;i<=n;i++){ + scanf("%d",&arr[i]); + + if(arr[i]max) + max = arr[i]; + + } + if(max - min > m){ + puts("NO"); + return 0; + } + puts("YES"); + for(i=1;i<=n;i++) { + for(j=1;j<=arr[i];j++) + printf("%d ",j + +int main(int argc, char *argv[]) +{ +int n,i,j; +scanf("%d",&n); + +if(n==1) + printf("1 0\n"); return 0; + +int arr[n]; + +for(i=0;i +#include +#include +#include +#include +#define oo 1000000000 +#define pi 3.14159265359 +#define zero(a) (abb(a)<=1e-7) +#define lowbit(a) ((a)&(-(a))) +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) +#define abb(a) ((a)>0?(a):(-(a))) +#define cj(x1,y1,x2,y2) ((x1)*(y2)-(x2)*(y2)) +#define dj(x1,y1,x2,y2) ((x1)*(y1)+(y1)*(y2)) +#define dis(x1,y1,x2,y2) sqrt(((x2)-(x1))*((x2)-(x1))+((y2)-(y1))*((y2)-(y1))) + +char a[111],b[111],c[111],d[111]; + +int main(int argc, char *argv[]) +{ + int m,t,x=1,y; + scanf("%d%d",&y,&m); + while (m--) + { + scanf("%s%s%s%s%d",a+1,b+1,c+1,d+1,&t); + if (c[1]=='l') + y=min(y,t-1); + else + x=max(x,t+1); + printf("%d\n",(y>=x)?y-x+1:-1); + } + return 0; +} diff --git a/src/main/resource/testFiles/codeflaws/revFiles/248-B-3757114-3757122.c b/src/main/resource/testFiles/codeflaws/revFiles/248-B-3757114-3757122.c new file mode 100644 index 0000000..64cbe86 --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/revFiles/248-B-3757114-3757122.c @@ -0,0 +1,21 @@ +#include +#include + +int main(int argc, char *argv[]) { + int n, suf[] = {170,20,200,110,50,80}, P = sizeof suf / sizeof *suf; + scanf ("%d", &n); + + if (n < 3) + printf ("-1\n"); + else if (n == 3) + printf ("210\n"); + else { + int i; + printf ("1"); + for (i = 0; i < n-4; ++i) + printf ("0"); + printf ("%.*d\n", 3, suf[n % P]); + } + exit (EXIT_SUCCESS); +return 0; +} diff --git a/src/main/resource/testFiles/codeflaws/revFiles/31-B-14288247-14288278.c b/src/main/resource/testFiles/codeflaws/revFiles/31-B-14288247-14288278.c new file mode 100644 index 0000000..d5cb4b6 --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/revFiles/31-B-14288247-14288278.c @@ -0,0 +1,27 @@ +#include + +int main(int argc, char *argv[]) { + char *p,*q,s[201]; + scanf("%s\n",s); + int ms=0; + for (p=s,q=p-2;*p;p++) { + if (*p=='@') { + if (p-q<3) break; + else q=p; + ms=1; + } + } + int first=1; + if (*p||*(p-1)=='@'||!ms) printf("No solution\n"); + else { + for (p=s+1,q=s;*p;p++,q++) { + if (*p=='@') { + if (!first) printf(","); + first=0; + } + printf("%c",*q); + } + printf("%s\n",q); + } + return 0; +} diff --git a/src/main/resource/testFiles/codeflaws/revFiles/430-B-10625991-10626001.c b/src/main/resource/testFiles/codeflaws/revFiles/430-B-10625991-10626001.c new file mode 100644 index 0000000..431a41d --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/revFiles/430-B-10625991-10626001.c @@ -0,0 +1,44 @@ +#include +int main(int argc, char *argv[]) +{ + int n,k,x,i,max=0,start,end; + scanf("%d%d%d",&n,&k,&x); + int A[n],consecutive[n-1],count=0,count2=0,temp,temp2,tempcount; + for(i=0;i=3) + tempcount=tempcount+count2; + + } + + if(tempcount>max) + max=tempcount; + } + printf("%d\n",max ); + return 0; +} \ No newline at end of file diff --git a/src/main/resource/testFiles/codeflaws/revFiles/494-A-10139010-10139025.c b/src/main/resource/testFiles/codeflaws/revFiles/494-A-10139010-10139025.c new file mode 100644 index 0000000..b10528f --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/revFiles/494-A-10139010-10139025.c @@ -0,0 +1,55 @@ +#include +#include +int main(int argc, char *argv[]){ + int flag,sum,max,sum1,i,j,k,l,n,m,h; + char c[100000]; + scanf("%s",c); + n = strlen(c); + h=0; + flag=1; + for(i=0;i0) || sum-h+1<=0) + flag=0; + sum1=0; + if(flag==0) + printf("-1\n"); + else{ + for(i=0;i +int main(int argc, char *argv[]) +{ +int n,a[200],i,max=0,j,b[100]; +scanf("%d",&n); +for(i=0;ib[i]) +max=b[i]; +printf("%d",max); +return 0; +} diff --git a/src/main/resource/testFiles/codeflaws/revFiles/509-B-11349359-11354327.c b/src/main/resource/testFiles/codeflaws/revFiles/509-B-11349359-11354327.c new file mode 100644 index 0000000..86a5069 --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/revFiles/509-B-11349359-11354327.c @@ -0,0 +1,27 @@ +#include +int arr[52000],i,j,n,m,max=-31231212,min=1123132; +int main(int argc, char *argv[]){ + scanf("%d %d",&n,&m); + for(i=1;i<=n;i++){ + scanf("%d",&arr[i]); + + if(arr[i]max) + max = arr[i]; + + } + if(max - min > m){ + puts("NO"); + return 0; + } + puts("YES"); + for(i=1;i<=n;i++) { + for(j=1;j<=arr[i];j++) + printf("%d ",j<=min ? 1 : j-min); + puts(""); + } + + return 0; +} diff --git a/src/main/resource/testFiles/codeflaws/revFiles/6-C-12776326-12776346.c b/src/main/resource/testFiles/codeflaws/revFiles/6-C-12776326-12776346.c new file mode 100644 index 0000000..8ecfb9b --- /dev/null +++ b/src/main/resource/testFiles/codeflaws/revFiles/6-C-12776326-12776346.c @@ -0,0 +1,70 @@ +#include + +int main(int argc, char *argv[]) +{ +int n,i,j; +scanf("%d",&n); + +if(n==1) +{ + printf("1 0\n"); return 0; +} + + +int arr[n]; + +for(i=0;i +#include +#include +#include +#include +#define oo 1000000000 +#define pi 3.14159265359 +#define zero(a) (abb(a)<=1e-7) +#define lowbit(a) ((a)&(-(a))) +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) +#define abb(a) ((a)>0?(a):(-(a))) +#define cj(x1,y1,x2,y2) ((x1)*(y2)-(x2)*(y2)) +#define dj(x1,y1,x2,y2) ((x1)*(y1)+(y1)*(y2)) +#define dis(x1,y1,x2,y2) sqrt(((x2)-(x1))*((x2)-(x1))+((y2)-(y1))*((y2)-(y1))) + +char a[111],b[111],c[111],d[111]; + +int main(int argc, char *argv[]) +{ + int m,t,x=1,y; + scanf("%d%d",&y,&m); + while (m--) + { + scanf("%s%s%s%s%d",a+1,b+1,c+1,d+1,&t); + if (c[1]=='l') + y=min(y,t-1); + else + x=max(x,t+1); + } + printf("%d\n",(y>=x)?y-x+1:-1); + return 0; +} diff --git a/src/main/resource/testFiles/cpython/prevFiles/prev_6a619f_46ab6d_Modules#posixmodule.c b/src/main/resource/testFiles/cpython/prevFiles/prev_6a619f_46ab6d_Modules#posixmodule.c new file mode 100644 index 0000000..2a1efa6 --- /dev/null +++ b/src/main/resource/testFiles/cpython/prevFiles/prev_6a619f_46ab6d_Modules#posixmodule.c @@ -0,0 +1,3493 @@ +/*********************************************************** +Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, +The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI or Corporation for National Research Initiatives or +CNRI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +While CWI is the initial source for this software, a modified version +is made available by the Corporation for National Research Initiatives +(CNRI) at the Internet address ftp://ftp.python.org. + +STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH +CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* POSIX module implementation */ + +/* This file is also used for Windows NT and MS-Win. In that case the module + actually calls itself 'nt', not 'posix', and a few functions are + either unimplemented or implemented differently. The source + assumes that for Windows NT, the macro 'MS_WIN32' is defined independent + of the compiler used. Different compilers define their own feature + test macro, e.g. '__BORLANDC__' or '_MSC_VER'. */ + +/* See also ../Dos/dosmodule.c */ + +static char posix__doc__ [] = +"This module provides access to operating system functionality that is\n\ +standardized by the C Standard and the POSIX standard (a thinly\n\ +disguised Unix interface). Refer to the library manual and\n\ +corresponding Unix manual entries for more information on calls."; + +#include "Python.h" + +#if defined(PYOS_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_DOSPROCESS +#define INCL_NOPMAPI +#include +#endif + +#include +#include +#ifdef HAVE_SYS_WAIT_H +#include /* For WNOHANG */ +#endif + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#include "mytime.h" /* For clock_t on some systems */ + +#ifdef HAVE_FCNTL_H +#include +#endif /* HAVE_FCNTL_H */ + +/* Various compilers have only certain posix functions */ +/* XXX Gosh I wish these were all moved into config.h */ +#if defined(PYCC_VACPP) && defined(PYOS_OS2) +#include +#else +#if defined(__WATCOMC__) && !defined(__QNX__) /* Watcom compiler */ +#define HAVE_GETCWD 1 +#define HAVE_OPENDIR 1 +#define HAVE_SYSTEM 1 +#if defined(__OS2__) +#define HAVE_EXECV 1 +#define HAVE_WAIT 1 +#endif +#include +#else +#ifdef __BORLANDC__ /* Borland compiler */ +#define HAVE_EXECV 1 +#define HAVE_GETCWD 1 +#define HAVE_GETEGID 1 +#define HAVE_GETEUID 1 +#define HAVE_GETGID 1 +#define HAVE_GETPPID 1 +#define HAVE_GETUID 1 +#define HAVE_KILL 1 +#define HAVE_OPENDIR 1 +#define HAVE_PIPE 1 +#define HAVE_POPEN 1 +#define HAVE_SYSTEM 1 +#define HAVE_WAIT 1 +#else +#ifdef _MSC_VER /* Microsoft compiler */ +#define HAVE_GETCWD 1 +#ifdef MS_WIN32 +#define HAVE_SPAWNV 1 +#define HAVE_EXECV 1 +#define HAVE_PIPE 1 +#define HAVE_POPEN 1 +#define HAVE_SYSTEM 1 +#else /* 16-bit Windows */ +#endif /* !MS_WIN32 */ +#else /* all other compilers */ +/* Unix functions that the configure script doesn't check for */ +#define HAVE_EXECV 1 +#define HAVE_FORK 1 +#define HAVE_GETCWD 1 +#define HAVE_GETEGID 1 +#define HAVE_GETEUID 1 +#define HAVE_GETGID 1 +#define HAVE_GETPPID 1 +#define HAVE_GETUID 1 +#define HAVE_KILL 1 +#define HAVE_OPENDIR 1 +#define HAVE_PIPE 1 +#define HAVE_POPEN 1 +#define HAVE_SYSTEM 1 +#define HAVE_WAIT 1 +#define HAVE_TTYNAME 1 +#endif /* _MSC_VER */ +#endif /* __BORLANDC__ */ +#endif /* ! __WATCOMC__ || __QNX__ */ +#endif /* ! __IBMC__ */ + +#ifndef _MSC_VER + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef NeXT +/* NeXT's and aren't worth much */ +#undef HAVE_UNISTD_H +#undef HAVE_UTIME_H +#define HAVE_WAITPID +/* #undef HAVE_GETCWD */ +#define UNION_WAIT /* This should really be checked for by autoconf */ +#endif + +#ifdef HAVE_UNISTD_H +/* XXX These are for SunOS4.1.3 but shouldn't hurt elsewhere */ +extern int rename(); +extern int pclose(); +extern int lstat(); +extern int symlink(); +extern int fsync(); +#else /* !HAVE_UNISTD_H */ +#if defined(PYCC_VACPP) +extern int mkdir Py_PROTO((char *)); +#else +#if ( defined(__WATCOMC__) || defined(_MSC_VER) ) && !defined(__QNX__) +extern int mkdir Py_PROTO((const char *)); +#else +extern int mkdir Py_PROTO((const char *, mode_t)); +#endif +#endif +#if defined(__IBMC__) || defined(__IBMCPP__) +extern int chdir Py_PROTO((char *)); +extern int rmdir Py_PROTO((char *)); +#else +extern int chdir Py_PROTO((const char *)); +extern int rmdir Py_PROTO((const char *)); +#endif +extern int chmod Py_PROTO((const char *, mode_t)); +extern int chown Py_PROTO((const char *, uid_t, gid_t)); +extern char *getcwd Py_PROTO((char *, int)); +extern char *strerror Py_PROTO((int)); +extern int link Py_PROTO((const char *, const char *)); +extern int rename Py_PROTO((const char *, const char *)); +extern int stat Py_PROTO((const char *, struct stat *)); +extern int unlink Py_PROTO((const char *)); +extern int pclose Py_PROTO((FILE *)); +#ifdef HAVE_SYMLINK +extern int symlink Py_PROTO((const char *, const char *)); +#endif /* HAVE_SYMLINK */ +#ifdef HAVE_LSTAT +extern int lstat Py_PROTO((const char *, struct stat *)); +#endif /* HAVE_LSTAT */ +#endif /* !HAVE_UNISTD_H */ + +#endif /* !_MSC_VER */ + +#ifdef HAVE_UTIME_H +#include +#endif /* HAVE_UTIME_H */ + +#ifdef HAVE_SYS_UTIME_H +#include +#define HAVE_UTIME_H /* pretend we do for the rest of this file */ +#endif /* HAVE_SYS_UTIME_H */ + +#ifdef HAVE_SYS_TIMES_H +#include +#endif /* HAVE_SYS_TIMES_H */ + +#ifdef HAVE_SYS_PARAM_H +#include +#endif /* HAVE_SYS_PARAM_H */ + +#ifdef HAVE_SYS_UTSNAME_H +#include +#endif /* HAVE_SYS_UTSNAME_H */ + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif /* MAXPATHLEN */ + +#ifdef HAVE_DIRENT_H +#include +#define NAMLEN(dirent) strlen((dirent)->d_name) +#else +#if defined(__WATCOMC__) && !defined(__QNX__) +#include +#define NAMLEN(dirent) strlen((dirent)->d_name) +#else +#define dirent direct +#define NAMLEN(dirent) (dirent)->d_namlen +#endif +#ifdef HAVE_SYS_NDIR_H +#include +#endif +#ifdef HAVE_SYS_DIR_H +#include +#endif +#ifdef HAVE_NDIR_H +#include +#endif +#endif + +#ifdef _MSC_VER +#include +#include +#include +#include +#ifdef MS_WIN32 +#define popen _popen +#define pclose _pclose +#else /* 16-bit Windows */ +#include +#include +#endif /* MS_WIN32 */ +#endif /* _MSC_VER */ + +#if defined(PYCC_VACPP) && defined(PYOS_OS2) +#include +#endif /* OS2 */ + +#ifdef UNION_WAIT +/* Emulate some macros on systems that have a union instead of macros */ + +#ifndef WIFEXITED +#define WIFEXITED(u_wait) (!(u_wait).w_termsig && !(u_wait).w_coredump) +#endif + +#ifndef WEXITSTATUS +#define WEXITSTATUS(u_wait) (WIFEXITED(u_wait)?((u_wait).w_retcode):-1) +#endif + +#ifndef WTERMSIG +#define WTERMSIG(u_wait) ((u_wait).w_termsig) +#endif + +#endif /* UNION_WAIT */ + +/* Return a dictionary corresponding to the POSIX environment table */ + +#if !defined(_MSC_VER) && ( !defined(__WATCOMC__) || defined(__QNX__) ) +extern char **environ; +#endif /* !_MSC_VER */ + +static PyObject * +convertenviron() +{ + PyObject *d; + char **e; + d = PyDict_New(); + if (d == NULL) + return NULL; + if (environ == NULL) + return d; + /* XXX This part ignores errors */ + for (e = environ; *e != NULL; e++) { + PyObject *v; + char *p = strchr(*e, '='); + if (p == NULL) + continue; + v = PyString_FromString(p+1); + if (v == NULL) + continue; + *p = '\0'; + if (PyDict_GetItemString(d, *e) == NULL) + (void) PyDict_SetItemString(d, *e, v); + *p = '='; + Py_DECREF(v); + } +#if defined(PYOS_OS2) + { + APIRET rc; + char buffer[1024]; /* OS/2 Provides a Documented Max of 1024 Chars */ + + rc = DosQueryExtLIBPATH(buffer, BEGIN_LIBPATH); + if (rc == NO_ERROR) { /* (not a type, envname is NOT 'BEGIN_LIBPATH') */ + PyObject *v = PyString_FromString(buffer); + PyDict_SetItemString(d, "BEGINLIBPATH", v); + Py_DECREF(v); + } + rc = DosQueryExtLIBPATH(buffer, END_LIBPATH); + if (rc == NO_ERROR) { /* (not a typo, envname is NOT 'END_LIBPATH') */ + PyObject *v = PyString_FromString(buffer); + PyDict_SetItemString(d, "ENDLIBPATH", v); + Py_DECREF(v); + } + } +#endif + return d; +} + + +/* Set a POSIX-specific error from errno, and return NULL */ + +static PyObject * +posix_error() +{ + return PyErr_SetFromErrno(PyExc_OSError); +} +static PyObject * +posix_error_with_filename(name) + char* name; +{ + return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); +} + + +#if defined(PYOS_OS2) +/********************************************************************** + * Helper Function to Trim and Format OS/2 Messages + **********************************************************************/ + static void +os2_formatmsg(char *msgbuf, int msglen, char *reason) +{ + msgbuf[msglen] = '\0'; /* OS/2 Doesn't Guarantee a Terminator */ + + if (strlen(msgbuf) > 0) { /* If Non-Empty Msg, Trim CRLF */ + char *lastc = &msgbuf[ strlen(msgbuf)-1 ]; + + while (lastc > msgbuf && isspace(*lastc)) + *lastc-- = '\0'; /* Trim Trailing Whitespace (CRLF) */ + } + + /* Add Optional Reason Text */ + if (reason) { + strcat(msgbuf, " : "); + strcat(msgbuf, reason); + } +} + +/********************************************************************** + * Decode an OS/2 Operating System Error Code + * + * A convenience function to lookup an OS/2 error code and return a + * text message we can use to raise a Python exception. + * + * Notes: + * The messages for errors returned from the OS/2 kernel reside in + * the file OSO001.MSG in the \OS2 directory hierarchy. + * + **********************************************************************/ + static char * +os2_strerror(char *msgbuf, int msgbuflen, int errorcode, char *reason) +{ + APIRET rc; + ULONG msglen; + + /* Retrieve Kernel-Related Error Message from OSO001.MSG File */ + Py_BEGIN_ALLOW_THREADS + rc = DosGetMessage(NULL, 0, msgbuf, msgbuflen, + errorcode, "oso001.msg", &msglen); + Py_END_ALLOW_THREADS + + if (rc == NO_ERROR) + os2_formatmsg(msgbuf, msglen, reason); + else + sprintf(msgbuf, "unknown OS error #%d", errorcode); + + return msgbuf; +} + +/* Set an OS/2-specific error and return NULL. OS/2 kernel + errors are not in a global variable e.g. 'errno' nor are + they congruent with posix error numbers. */ + +static PyObject * os2_error(int code) +{ + char text[1024]; + PyObject *v; + + os2_strerror(text, sizeof(text), code, ""); + + v = Py_BuildValue("(is)", code, text); + if (v != NULL) { + PyErr_SetObject(PyExc_OSError, v); + Py_DECREF(v); + } + return NULL; /* Signal to Python that an Exception is Pending */ +} + +#endif /* OS2 */ + +/* POSIX generic methods */ + +static PyObject * +posix_int(args, func) + PyObject *args; + int (*func) Py_FPROTO((int)); +{ + int fd; + int res; + if (!PyArg_Parse(args, "i", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(fd); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +posix_1str(args, func) + PyObject *args; + int (*func) Py_FPROTO((const char *)); +{ + char *path1; + int res; + if (!PyArg_Parse(args, "s", &path1)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(path1); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_filename(path1); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +posix_2str(args, func) + PyObject *args; + int (*func) Py_FPROTO((const char *, const char *)); +{ + char *path1, *path2; + int res; + if (!PyArg_Parse(args, "(ss)", &path1, &path2)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(path1, path2); + Py_END_ALLOW_THREADS + if (res != 0) + /* XXX how to report both path1 and path2??? */ + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +posix_strint(args, func) + PyObject *args; + int (*func) Py_FPROTO((const char *, int)); +{ + char *path; + int i; + int res; + if (!PyArg_Parse(args, "(si)", &path, &i)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(path, i); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_filename(path); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +posix_strintint(args, func) + PyObject *args; + int (*func) Py_FPROTO((const char *, int, int)); +{ + char *path; + int i,i2; + int res; + if (!PyArg_Parse(args, "(sii)", &path, &i, &i2)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(path, i, i2); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_filename(path); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +posix_do_stat(self, args, statfunc) + PyObject *self; + PyObject *args; + int (*statfunc) Py_FPROTO((const char *, struct stat *)); +{ + struct stat st; + char *path; + int res; + if (!PyArg_Parse(args, "s", &path)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*statfunc)(path, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error_with_filename(path); +#if !defined(HAVE_LARGEFILE_SUPPORT) + return Py_BuildValue("(llllllllll)", + (long)st.st_mode, + (long)st.st_ino, + (long)st.st_dev, + (long)st.st_nlink, + (long)st.st_uid, + (long)st.st_gid, + (long)st.st_size, + (long)st.st_atime, + (long)st.st_mtime, + (long)st.st_ctime); +#else + return Py_BuildValue("(lLllllLlll)", + (long)st.st_mode, + (LONG_LONG)st.st_ino, + (long)st.st_dev, + (long)st.st_nlink, + (long)st.st_uid, + (long)st.st_gid, + (LONG_LONG)st.st_size, + (long)st.st_atime, + (long)st.st_mtime, + (long)st.st_ctime); +#endif +} + + +/* POSIX methods */ + +static char posix_access__doc__[] = +"access(path, mode) -> 1 if granted, 0 otherwise\n\ +Test for access to a file."; + +static PyObject * +posix_access(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + int mode; + int res; + + if (!PyArg_Parse(args, "(si)", &path, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = access(path, mode); + Py_END_ALLOW_THREADS + return(PyInt_FromLong(res == 0 ? 1L : 0L)); +} + +#ifndef F_OK +#define F_OK 0 +#endif +#ifndef R_OK +#define R_OK 4 +#endif +#ifndef W_OK +#define W_OK 2 +#endif +#ifndef X_OK +#define X_OK 1 +#endif + +#ifdef HAVE_TTYNAME +static char posix_ttyname__doc__[] = +"ttyname(fd) -> String\n\ +Return the name of the terminal device connected to 'fd'."; + +static PyObject * +posix_ttyname(self, args) + PyObject *self; + PyObject *args; +{ + PyObject *file; + int id; + char *ret; + + if (!PyArg_Parse(args, "i", &id)) + return NULL; + + ret = ttyname(id); + if (ret == NULL) + return(posix_error()); + return(PyString_FromString(ret)); +} +#endif + +static char posix_chdir__doc__[] = +"chdir(path) -> None\n\ +Change the current working directory to the specified path."; + +static PyObject * +posix_chdir(self, args) + PyObject *self; + PyObject *args; +{ + return posix_1str(args, chdir); +} + + +static char posix_chmod__doc__[] = +"chmod(path, mode) -> None\n\ +Change the access permissions of a file."; + +static PyObject * +posix_chmod(self, args) + PyObject *self; + PyObject *args; +{ + return posix_strint(args, chmod); +} + + +#ifdef HAVE_FSYNC +static char posix_fsync__doc__[] = +"fsync(fildes) -> None\n\ +force write of file with filedescriptor to disk."; + +static PyObject * +posix_fsync(self, args) + PyObject *self; + PyObject *args; +{ + return posix_int(args, fsync); +} +#endif /* HAVE_FSYNC */ + +#ifdef HAVE_FDATASYNC +static char posix_fdatasync__doc__[] = +"fdatasync(fildes) -> None\n\ +force write of file with filedescriptor to disk.\n\ + does not force update of metadata."; + +extern int fdatasync(int); /* Prototype just in case */ + +static PyObject * +posix_fdatasync(self, args) + PyObject *self; + PyObject *args; +{ + return posix_int(args, fdatasync); +} +#endif /* HAVE_FDATASYNC */ + + +#ifdef HAVE_CHOWN +static char posix_chown__doc__[] = +"chown(path, uid, gid) -> None\n\ +Change the owner and group id of path to the numeric uid and gid."; + +static PyObject * +posix_chown(self, args) + PyObject *self; + PyObject *args; +{ + return posix_strintint(args, chown); +} +#endif /* HAVE_CHOWN */ + + +#ifdef HAVE_GETCWD +static char posix_getcwd__doc__[] = +"getcwd() -> path\n\ +Return a string representing the current working directory."; + +static PyObject * +posix_getcwd(self, args) + PyObject *self; + PyObject *args; +{ + char buf[1026]; + char *res; + if (!PyArg_NoArgs(args)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = getcwd(buf, sizeof buf); + Py_END_ALLOW_THREADS + if (res == NULL) + return posix_error(); + return PyString_FromString(buf); +} +#endif + + +#ifdef HAVE_LINK +static char posix_link__doc__[] = +"link(src, dst) -> None\n\ +Create a hard link to a file."; + +static PyObject * +posix_link(self, args) + PyObject *self; + PyObject *args; +{ + return posix_2str(args, link); +} +#endif /* HAVE_LINK */ + + +static char posix_listdir__doc__[] = +"listdir(path) -> list_of_strings\n\ +Return a list containing the names of the entries in the directory.\n\ +\n\ + path: path of directory to list\n\ +\n\ +The list is in arbitrary order. It does not include the special\n\ +entries '.' and '..' even if they are present in the directory."; + +static PyObject * +posix_listdir(self, args) + PyObject *self; + PyObject *args; +{ + /* XXX Should redo this putting the (now four) versions of opendir + in separate files instead of having them all here... */ +#if defined(MS_WIN32) && !defined(HAVE_OPENDIR) + + char *name; + int len; + PyObject *d, *v; + HANDLE hFindFile; + WIN32_FIND_DATA FileData; + char namebuf[MAX_PATH+5]; + + if (!PyArg_Parse(args, "t#", &name, &len)) + return NULL; + if (len >= MAX_PATH) { + PyErr_SetString(PyExc_ValueError, "path too long"); + return NULL; + } + strcpy(namebuf, name); + if (namebuf[len-1] != '/' && namebuf[len-1] != '\\') + namebuf[len++] = '/'; + strcpy(namebuf + len, "*.*"); + + if ((d = PyList_New(0)) == NULL) + return NULL; + + hFindFile = FindFirstFile(namebuf, &FileData); + if (hFindFile == INVALID_HANDLE_VALUE) { + errno = GetLastError(); + if (errno == ERROR_FILE_NOT_FOUND) + return PyList_New(0); + return posix_error_with_filename(name); + } + do { + if (FileData.cFileName[0] == '.' && + (FileData.cFileName[1] == '\0' || + FileData.cFileName[1] == '.' && + FileData.cFileName[2] == '\0')) + continue; + v = PyString_FromString(FileData.cFileName); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } while (FindNextFile(hFindFile, &FileData) == TRUE); + + if (FindClose(hFindFile) == FALSE) { + errno = GetLastError(); + return posix_error_with_filename(&name); + } + + return d; + +#else /* !MS_WIN32 */ +#ifdef _MSC_VER /* 16-bit Windows */ + +#ifndef MAX_PATH +#define MAX_PATH 250 +#endif + char *name, *pt; + int len; + PyObject *d, *v; + char namebuf[MAX_PATH+5]; + struct _find_t ep; + + if (!PyArg_Parse(args, "t#", &name, &len)) + return NULL; + if (len >= MAX_PATH) { + PyErr_SetString(PyExc_ValueError, "path too long"); + return NULL; + } + strcpy(namebuf, name); + for (pt = namebuf; *pt; pt++) + if (*pt == '/') + *pt = '\\'; + if (namebuf[len-1] != '\\') + namebuf[len++] = '\\'; + strcpy(namebuf + len, "*.*"); + + if ((d = PyList_New(0)) == NULL) + return NULL; + + if (_dos_findfirst(namebuf, _A_RDONLY | + _A_HIDDEN | _A_SYSTEM | _A_SUBDIR, &ep) != 0) + { + errno = ENOENT; + return posix_error_with_filename(name); + } + do { + if (ep.name[0] == '.' && + (ep.name[1] == '\0' || + ep.name[1] == '.' && + ep.name[2] == '\0')) + continue; + strcpy(namebuf, ep.name); + for (pt = namebuf; *pt; pt++) + if (isupper(*pt)) + *pt = tolower(*pt); + v = PyString_FromString(namebuf); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } while (_dos_findnext(&ep) == 0); + + return d; + +#else +#if defined(PYOS_OS2) + +#ifndef MAX_PATH +#define MAX_PATH CCHMAXPATH +#endif + char *name, *pt; + int len; + PyObject *d, *v; + char namebuf[MAX_PATH+5]; + HDIR hdir = 1; + ULONG srchcnt = 1; + FILEFINDBUF3 ep; + APIRET rc; + + if (!PyArg_Parse(args, "t#", &name, &len)) + return NULL; + if (len >= MAX_PATH) { + PyErr_SetString(PyExc_ValueError, "path too long"); + return NULL; + } + strcpy(namebuf, name); + for (pt = namebuf; *pt; pt++) + if (*pt == '/') + *pt = '\\'; + if (namebuf[len-1] != '\\') + namebuf[len++] = '\\'; + strcpy(namebuf + len, "*.*"); + + if ((d = PyList_New(0)) == NULL) + return NULL; + + rc = DosFindFirst(namebuf, /* Wildcard Pattern to Match */ + &hdir, /* Handle to Use While Search Directory */ + FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY, + &ep, sizeof(ep), /* Structure to Receive Directory Entry */ + &srchcnt, /* Max and Actual Count of Entries Per Iteration */ + FIL_STANDARD); /* Format of Entry (EAs or Not) */ + + if (rc != NO_ERROR) { + errno = ENOENT; + return posix_error_with_filename(name); + } + + if (srchcnt > 0) { /* If Directory is NOT Totally Empty, */ + do { + if (ep.achName[0] == '.' + && (ep.achName[1] == '\0' || ep.achName[1] == '.' && ep.achName[2] == '\0')) + continue; /* Skip Over "." and ".." Names */ + + strcpy(namebuf, ep.achName); + + /* Leave Case of Name Alone -- In Native Form */ + /* (Removed Forced Lowercasing Code) */ + + v = PyString_FromString(namebuf); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } while (DosFindNext(hdir, &ep, sizeof(ep), &srchcnt) == NO_ERROR && srchcnt > 0); + } + + return d; +#else + + char *name; + PyObject *d, *v; + DIR *dirp; + struct dirent *ep; + if (!PyArg_Parse(args, "s", &name)) + return NULL; + Py_BEGIN_ALLOW_THREADS + if ((dirp = opendir(name)) == NULL) { + Py_BLOCK_THREADS + return posix_error_with_filename(name); + } + if ((d = PyList_New(0)) == NULL) { + closedir(dirp); + Py_BLOCK_THREADS + return NULL; + } + while ((ep = readdir(dirp)) != NULL) { + if (ep->d_name[0] == '.' && + (NAMLEN(ep) == 1 || + (ep->d_name[1] == '.' && NAMLEN(ep) == 2))) + continue; + v = PyString_FromStringAndSize(ep->d_name, NAMLEN(ep)); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } + closedir(dirp); + Py_END_ALLOW_THREADS + + return d; + +#endif /* !PYOS_OS2 */ +#endif /* !_MSC_VER */ +#endif /* !MS_WIN32 */ +} + +static char posix_mkdir__doc__[] = +"mkdir(path [, mode=0777]) -> None\n\ +Create a directory."; + +static PyObject * +posix_mkdir(self, args) + PyObject *self; + PyObject *args; +{ + int res; + char *path; + int mode = 0777; + if (!PyArg_ParseTuple(args, "s|i", &path, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS +#if ( defined(__WATCOMC__) || defined(_MSC_VER) || defined(PYCC_VACPP) ) && !defined(__QNX__) + res = mkdir(path); +#else + res = mkdir(path, mode); +#endif + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_filename(path); + Py_INCREF(Py_None); + return Py_None; +} + + +#ifdef HAVE_NICE +static char posix_nice__doc__[] = +"nice(inc) -> new_priority\n\ +Decrease the priority of process and return new priority."; + +static PyObject * +posix_nice(self, args) + PyObject *self; + PyObject *args; +{ + int increment, value; + + if (!PyArg_Parse(args, "i", &increment)) + return NULL; + value = nice(increment); + if (value == -1) + return posix_error(); + return PyInt_FromLong((long) value); +} +#endif /* HAVE_NICE */ + + +static char posix_rename__doc__[] = +"rename(old, new) -> None\n\ +Rename a file or directory."; + +static PyObject * +posix_rename(self, args) + PyObject *self; + PyObject *args; +{ + return posix_2str(args, rename); +} + + +static char posix_rmdir__doc__[] = +"rmdir(path) -> None\n\ +Remove a directory."; + +static PyObject * +posix_rmdir(self, args) + PyObject *self; + PyObject *args; +{ + return posix_1str(args, rmdir); +} + + +static char posix_stat__doc__[] = +"stat(path) -> (mode,ino,dev,nlink,uid,gid,size,atime,mtime,ctime)\n\ +Perform a stat system call on the given path."; + +static PyObject * +posix_stat(self, args) + PyObject *self; + PyObject *args; +{ + return posix_do_stat(self, args, stat); +} + + +#ifdef HAVE_SYSTEM +static char posix_system__doc__[] = +"system(command) -> exit_status\n\ +Execute the command (a string) in a subshell."; + +static PyObject * +posix_system(self, args) + PyObject *self; + PyObject *args; +{ + char *command; + long sts; + if (!PyArg_Parse(args, "s", &command)) + return NULL; + Py_BEGIN_ALLOW_THREADS + sts = system(command); + Py_END_ALLOW_THREADS + return PyInt_FromLong(sts); +} +#endif + + +static char posix_umask__doc__[] = +"umask(new_mask) -> old_mask\n\ +Set the current numeric umask and return the previous umask."; + +static PyObject * +posix_umask(self, args) + PyObject *self; + PyObject *args; +{ + int i; + if (!PyArg_Parse(args, "i", &i)) + return NULL; + i = umask(i); + if (i < 0) + return posix_error(); + return PyInt_FromLong((long)i); +} + + +static char posix_unlink__doc__[] = +"unlink(path) -> None\n\ +Remove a file (same as remove(path))."; + +static char posix_remove__doc__[] = +"remove(path) -> None\n\ +Remove a file (same as unlink(path))."; + +static PyObject * +posix_unlink(self, args) + PyObject *self; + PyObject *args; +{ + return posix_1str(args, unlink); +} + + +#ifdef HAVE_UNAME +static char posix_uname__doc__[] = +"uname() -> (sysname, nodename, release, version, machine)\n\ +Return a tuple identifying the current operating system."; + +static PyObject * +posix_uname(self, args) + PyObject *self; + PyObject *args; +{ + struct utsname u; + int res; + if (!PyArg_NoArgs(args)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = uname(&u); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + return Py_BuildValue("(sssss)", + u.sysname, + u.nodename, + u.release, + u.version, + u.machine); +} +#endif /* HAVE_UNAME */ + + +static char posix_utime__doc__[] = +"utime(path, (atime, utime)) -> None\n\ +Set the access and modified time of the file to the given values."; + +static PyObject * +posix_utime(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + long atime, mtime; + int res; + +/* XXX should define struct utimbuf instead, above */ +#ifdef HAVE_UTIME_H + struct utimbuf buf; +#define ATIME buf.actime +#define MTIME buf.modtime +#define UTIME_ARG &buf +#else /* HAVE_UTIME_H */ + time_t buf[2]; +#define ATIME buf[0] +#define MTIME buf[1] +#define UTIME_ARG buf +#endif /* HAVE_UTIME_H */ + + if (!PyArg_Parse(args, "(s(ll))", &path, &atime, &mtime)) + return NULL; + ATIME = atime; + MTIME = mtime; + Py_BEGIN_ALLOW_THREADS + res = utime(path, UTIME_ARG); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_filename(path); + Py_INCREF(Py_None); + return Py_None; +#undef UTIME_ARG +#undef ATIME +#undef MTIME +} + + +/* Process operations */ + +static char posix__exit__doc__[] = +"_exit(status)\n\ +Exit to the system with specified status, without normal exit processing."; + +static PyObject * +posix__exit(self, args) + PyObject *self; + PyObject *args; +{ + int sts; + if (!PyArg_Parse(args, "i", &sts)) + return NULL; + _exit(sts); + return NULL; /* Make gcc -Wall happy */ +} + + +#ifdef HAVE_EXECV +static char posix_execv__doc__[] = +"execv(path, args)\n\ +Execute an executable path with arguments, replacing current process.\n\ +\n\ + path: path of executable file\n\ + args: tuple or list of strings"; + +static PyObject * +posix_execv(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + PyObject *argv; + char **argvlist; + int i, argc; + PyObject *(*getitem) Py_PROTO((PyObject *, int)); + + /* execv has two arguments: (path, argv), where + argv is a list or tuple of strings. */ + + if (!PyArg_Parse(args, "(sO)", &path, &argv)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + badarg: + PyErr_BadArgument(); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) + return NULL; + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), "s", &argvlist[i])) { + PyMem_DEL(argvlist); + goto badarg; + } + } + argvlist[argc] = NULL; + +#ifdef BAD_EXEC_PROTOTYPES + execv(path, (const char **) argvlist); +#else /* BAD_EXEC_PROTOTYPES */ + execv(path, argvlist); +#endif /* BAD_EXEC_PROTOTYPES */ + + /* If we get here it's definitely an error */ + + PyMem_DEL(argvlist); + return posix_error(); +} + + +static char posix_execve__doc__[] = +"execve(path, args, env)\n\ +Execute a path with arguments and environment, replacing current process.\n\ +\n\ + path: path of executable file\n\ + args: tuple or list of arguments\n\ + env: dictonary of strings mapping to strings"; + +static PyObject * +posix_execve(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + PyObject *argv, *env; + char **argvlist; + char **envlist; + PyObject *key, *val, *keys=NULL, *vals=NULL; + int i, pos, argc, envc; + PyObject *(*getitem) Py_PROTO((PyObject *, int)); + + /* execve has three arguments: (path, argv, env), where + argv is a list or tuple of strings and env is a dictionary + like posix.environ. */ + + if (!PyArg_Parse(args, "(sOO)", &path, &argv, &env)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + PyErr_SetString(PyExc_TypeError, "argv must be tuple or list"); + return NULL; + } + if (!PyMapping_Check(env)) { + PyErr_SetString(PyExc_TypeError, "env must be mapping object"); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) { + PyErr_NoMemory(); + return NULL; + } + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), + "s;argv must be list of strings", + &argvlist[i])) + { + goto fail_1; + } + } + argvlist[argc] = NULL; + + i = PyMapping_Length(env); + envlist = PyMem_NEW(char *, i + 1); + if (envlist == NULL) { + PyErr_NoMemory(); + goto fail_1; + } + envc = 0; + keys = PyMapping_Keys(env); + vals = PyMapping_Values(env); + if (!keys || !vals) + goto fail_2; + + for (pos = 0; pos < i; pos++) { + char *p, *k, *v; + + key = PyList_GetItem(keys, pos); + val = PyList_GetItem(vals, pos); + if (!key || !val) + goto fail_2; + + if (!PyArg_Parse(key, "s;non-string key in env", &k) || + !PyArg_Parse(val, "s;non-string value in env", &v)) + { + goto fail_2; + } + +#if defined(PYOS_OS2) + /* Omit Pseudo-Env Vars that Would Confuse Programs if Passed On */ + if (stricmp(k, "BEGINLIBPATH") != 0 && stricmp(k, "ENDLIBPATH") != 0) { +#endif + p = PyMem_NEW(char, PyString_Size(key)+PyString_Size(val) + 2); + if (p == NULL) { + PyErr_NoMemory(); + goto fail_2; + } + sprintf(p, "%s=%s", k, v); + envlist[envc++] = p; +#if defined(PYOS_OS2) + } +#endif + } + envlist[envc] = 0; + + +#ifdef BAD_EXEC_PROTOTYPES + execve(path, (const char **)argvlist, envlist); +#else /* BAD_EXEC_PROTOTYPES */ + execve(path, argvlist, envlist); +#endif /* BAD_EXEC_PROTOTYPES */ + + /* If we get here it's definitely an error */ + + (void) posix_error(); + + fail_2: + while (--envc >= 0) + PyMem_DEL(envlist[envc]); + PyMem_DEL(envlist); + fail_1: + PyMem_DEL(argvlist); + Py_XDECREF(vals); + Py_XDECREF(keys); + return NULL; +} +#endif /* HAVE_EXECV */ + + +#ifdef HAVE_SPAWNV +static char posix_spawnv__doc__[] = +"spawnv(mode, path, args)\n\ +Execute an executable path with arguments, replacing current process.\n\ +\n\ + mode: mode of process creation\n\ + path: path of executable file\n\ + args: tuple or list of strings"; + +static PyObject * +posix_spawnv(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + PyObject *argv; + char **argvlist; + int mode, i, argc; + PyObject *(*getitem) Py_PROTO((PyObject *, int)); + + /* spawnv has three arguments: (mode, path, argv), where + argv is a list or tuple of strings. */ + + if (!PyArg_Parse(args, "(isO)", &mode, &path, &argv)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + badarg: + PyErr_BadArgument(); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) + return NULL; + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), "s", &argvlist[i])) { + PyMem_DEL(argvlist); + goto badarg; + } + } + argvlist[argc] = NULL; + + if (mode == _OLD_P_OVERLAY) + mode = _P_OVERLAY; + i = _spawnv(mode, path, argvlist); + + PyMem_DEL(argvlist); + + if (i == -1) + return posix_error(); + else + return Py_BuildValue("i", i); +} + + +static char posix_spawnve__doc__[] = +"spawnve(mode, path, args, env)\n\ +Execute a path with arguments and environment, replacing current process.\n\ +\n\ + mode: mode of process creation\n\ + path: path of executable file\n\ + args: tuple or list of arguments\n\ + env: dictonary of strings mapping to strings"; + +static PyObject * +posix_spawnve(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + PyObject *argv, *env; + char **argvlist; + char **envlist; + PyObject *key, *val, *keys=NULL, *vals=NULL, *res=NULL; + int mode, i, pos, argc, envc; + PyObject *(*getitem) Py_PROTO((PyObject *, int)); + + /* spawnve has four arguments: (mode, path, argv, env), where + argv is a list or tuple of strings and env is a dictionary + like posix.environ. */ + + if (!PyArg_Parse(args, "(isOO)", &mode, &path, &argv, &env)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + PyErr_SetString(PyExc_TypeError, "argv must be tuple or list"); + return NULL; + } + if (!PyMapping_Check(env)) { + PyErr_SetString(PyExc_TypeError, "env must be mapping object"); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) { + PyErr_NoMemory(); + return NULL; + } + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), + "s;argv must be list of strings", + &argvlist[i])) + { + goto fail_1; + } + } + argvlist[argc] = NULL; + + i = PyMapping_Length(env); + envlist = PyMem_NEW(char *, i + 1); + if (envlist == NULL) { + PyErr_NoMemory(); + goto fail_1; + } + envc = 0; + keys = PyMapping_Keys(env); + vals = PyMapping_Values(env); + if (!keys || !vals) + goto fail_2; + + for (pos = 0; pos < i; pos++) { + char *p, *k, *v; + + key = PyList_GetItem(keys, pos); + val = PyList_GetItem(vals, pos); + if (!key || !val) + goto fail_2; + + if (!PyArg_Parse(key, "s;non-string key in env", &k) || + !PyArg_Parse(val, "s;non-string value in env", &v)) + { + goto fail_2; + } + p = PyMem_NEW(char, PyString_Size(key)+PyString_Size(val) + 2); + if (p == NULL) { + PyErr_NoMemory(); + goto fail_2; + } + sprintf(p, "%s=%s", k, v); + envlist[envc++] = p; + } + envlist[envc] = 0; + + if (mode == _OLD_P_OVERLAY) + mode = _P_OVERLAY; + i = _spawnve(mode, path, argvlist, envlist); + if (i == -1) + (void) posix_error(); + else + res = Py_BuildValue("i", i); + + fail_2: + while (--envc >= 0) + PyMem_DEL(envlist[envc]); + PyMem_DEL(envlist); + fail_1: + PyMem_DEL(argvlist); + Py_XDECREF(vals); + Py_XDECREF(keys); + return res; +} +#endif /* HAVE_SPAWNV */ + + +#ifdef HAVE_FORK +static char posix_fork__doc__[] = +"fork() -> pid\n\ +Fork a child process.\n\ +\n\ +Return 0 to child process and PID of child to parent process."; + +static PyObject * +posix_fork(self, args) + PyObject *self; + PyObject *args; +{ + int pid; + if (!PyArg_NoArgs(args)) + return NULL; + pid = fork(); + if (pid == -1) + return posix_error(); + PyOS_AfterFork(); + return PyInt_FromLong((long)pid); +} +#endif + + +#ifdef HAVE_GETEGID +static char posix_getegid__doc__[] = +"getegid() -> egid\n\ +Return the current process's effective group id."; + +static PyObject * +posix_getegid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)getegid()); +} +#endif + + +#ifdef HAVE_GETEUID +static char posix_geteuid__doc__[] = +"geteuid() -> euid\n\ +Return the current process's effective user id."; + +static PyObject * +posix_geteuid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)geteuid()); +} +#endif + + +#ifdef HAVE_GETGID +static char posix_getgid__doc__[] = +"getgid() -> gid\n\ +Return the current process's group id."; + +static PyObject * +posix_getgid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)getgid()); +} +#endif + + +static char posix_getpid__doc__[] = +"getpid() -> pid\n\ +Return the current process id"; + +static PyObject * +posix_getpid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)getpid()); +} + + +#ifdef HAVE_GETPGRP +static char posix_getpgrp__doc__[] = +"getpgrp() -> pgrp\n\ +Return the current process group id."; + +static PyObject * +posix_getpgrp(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; +#ifdef GETPGRP_HAVE_ARG + return PyInt_FromLong((long)getpgrp(0)); +#else /* GETPGRP_HAVE_ARG */ + return PyInt_FromLong((long)getpgrp()); +#endif /* GETPGRP_HAVE_ARG */ +} +#endif /* HAVE_GETPGRP */ + + +#ifdef HAVE_SETPGRP +static char posix_setpgrp__doc__[] = +"setpgrp() -> None\n\ +Make this process a session leader."; + +static PyObject * +posix_setpgrp(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; +#ifdef SETPGRP_HAVE_ARG + if (setpgrp(0, 0) < 0) +#else /* SETPGRP_HAVE_ARG */ + if (setpgrp() < 0) +#endif /* SETPGRP_HAVE_ARG */ + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + +#endif /* HAVE_SETPGRP */ + +#ifdef HAVE_GETPPID +static char posix_getppid__doc__[] = +"getppid() -> ppid\n\ +Return the parent's process id."; + +static PyObject * +posix_getppid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)getppid()); +} +#endif + + +#ifdef HAVE_GETUID +static char posix_getuid__doc__[] = +"getuid() -> uid\n\ +Return the current process's user id."; + +static PyObject * +posix_getuid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)getuid()); +} +#endif + + +#ifdef HAVE_KILL +static char posix_kill__doc__[] = +"kill(pid, sig) -> None\n\ +Kill a process with a signal."; + +static PyObject * +posix_kill(self, args) + PyObject *self; + PyObject *args; +{ + int pid, sig; + if (!PyArg_Parse(args, "(ii)", &pid, &sig)) + return NULL; +#if defined(PYOS_OS2) + if (sig == XCPT_SIGNAL_INTR || sig == XCPT_SIGNAL_BREAK) { + APIRET rc; + if ((rc = DosSendSignalException(pid, sig)) != NO_ERROR) + return os2_error(rc); + + } else if (sig == XCPT_SIGNAL_KILLPROC) { + APIRET rc; + if ((rc = DosKillProcess(DKP_PROCESS, pid)) != NO_ERROR) + return os2_error(rc); + + } else + return NULL; /* Unrecognized Signal Requested */ +#else + if (kill(pid, sig) == -1) + return posix_error(); +#endif + Py_INCREF(Py_None); + return Py_None; +} +#endif + +#ifdef HAVE_PLOCK + +#ifdef HAVE_SYS_LOCK_H +#include +#endif + +static char posix_plock__doc__[] = +"plock(op) -> None\n\ +Lock program segments into memory."; + +static PyObject * +posix_plock(self, args) + PyObject *self; + PyObject *args; +{ + int op; + if (!PyArg_Parse(args, "i", &op)) + return NULL; + if (plock(op) == -1) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif + + +#ifdef HAVE_POPEN +static char posix_popen__doc__[] = +"popen(command [, mode='r' [, bufsize]]) -> pipe\n\ +Open a pipe to/from a command returning a file object."; + +#if defined(PYOS_OS2) +static int +async_system(const char *command) +{ + char *p, errormsg[256], args[1024]; + RESULTCODES rcodes; + APIRET rc; + char *shell = getenv("COMSPEC"); + if (!shell) + shell = "cmd"; + + strcpy(args, shell); + p = &args[ strlen(args)+1 ]; + strcpy(p, "/c "); + strcat(p, command); + p += strlen(p) + 1; + *p = '\0'; + + rc = DosExecPgm(errormsg, sizeof(errormsg), + EXEC_ASYNC, /* Execute Async w/o Wait for Results */ + args, + NULL, /* Inherit Parent's Environment */ + &rcodes, shell); + return rc; +} + +static FILE * +popen(const char *command, const char *mode, int pipesize, int *err) +{ + HFILE rhan, whan; + FILE *retfd = NULL; + APIRET rc = DosCreatePipe(&rhan, &whan, pipesize); + + if (rc != NO_ERROR) { + *err = rc; + return NULL; /* ERROR - Unable to Create Anon Pipe */ + } + + if (strchr(mode, 'r') != NULL) { /* Treat Command as a Data Source */ + int oldfd = dup(1); /* Save STDOUT Handle in Another Handle */ + + DosEnterCritSec(); /* Stop Other Threads While Changing Handles */ + close(1); /* Make STDOUT Available for Reallocation */ + + if (dup2(whan, 1) == 0) { /* Connect STDOUT to Pipe Write Side */ + DosClose(whan); /* Close Now-Unused Pipe Write Handle */ + + if (async_system(command) == NO_ERROR) + retfd = fdopen(rhan, mode); /* And Return Pipe Read Handle */ + } + + dup2(oldfd, 1); /* Reconnect STDOUT to Original Handle */ + DosExitCritSec(); /* Now Allow Other Threads to Run */ + + close(oldfd); /* And Close Saved STDOUT Handle */ + return retfd; /* Return fd of Pipe or NULL if Error */ + + } else if (strchr(mode, 'w')) { /* Treat Command as a Data Sink */ + int oldfd = dup(0); /* Save STDIN Handle in Another Handle */ + + DosEnterCritSec(); /* Stop Other Threads While Changing Handles */ + close(0); /* Make STDIN Available for Reallocation */ + + if (dup2(rhan, 0) == 0) { /* Connect STDIN to Pipe Read Side */ + DosClose(rhan); /* Close Now-Unused Pipe Read Handle */ + + if (async_system(command) == NO_ERROR) + retfd = fdopen(whan, mode); /* And Return Pipe Write Handle */ + } + + dup2(oldfd, 0); /* Reconnect STDIN to Original Handle */ + DosExitCritSec(); /* Now Allow Other Threads to Run */ + + close(oldfd); /* And Close Saved STDIN Handle */ + return retfd; /* Return fd of Pipe or NULL if Error */ + + } else { + *err = ERROR_INVALID_ACCESS; + return NULL; /* ERROR - Invalid Mode (Neither Read nor Write) */ + } +} + +static PyObject * +posix_popen(self, args) + PyObject *self; + PyObject *args; +{ + char *name; + char *mode = "r"; + int err, bufsize = -1; + FILE *fp; + PyObject *f; + if (!PyArg_ParseTuple(args, "s|si", &name, &mode, &bufsize)) + return NULL; + Py_BEGIN_ALLOW_THREADS + fp = popen(name, mode, (bufsize > 0) ? bufsize : 4096, &err); + Py_END_ALLOW_THREADS + if (fp == NULL) + return os2_error(err); + + f = PyFile_FromFile(fp, name, mode, fclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} + +#else +static PyObject * +posix_popen(self, args) + PyObject *self; + PyObject *args; +{ + char *name; + char *mode = "r"; + int bufsize = -1; + FILE *fp; + PyObject *f; + if (!PyArg_ParseTuple(args, "s|si", &name, &mode, &bufsize)) + return NULL; + Py_BEGIN_ALLOW_THREADS + fp = popen(name, mode); + Py_END_ALLOW_THREADS + if (fp == NULL) + return posix_error(); + f = PyFile_FromFile(fp, name, mode, pclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} +#endif + +#endif /* HAVE_POPEN */ + + +#ifdef HAVE_SETUID +static char posix_setuid__doc__[] = +"setuid(uid) -> None\n\ +Set the current process's user id."; +static PyObject * +posix_setuid(self, args) + PyObject *self; + PyObject *args; +{ + int uid; + if (!PyArg_Parse(args, "i", &uid)) + return NULL; + if (setuid(uid) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETUID */ + + +#ifdef HAVE_SETGID +static char posix_setgid__doc__[] = +"setgid(gid) -> None\n\ +Set the current process's group id."; + +static PyObject * +posix_setgid(self, args) + PyObject *self; + PyObject *args; +{ + int gid; + if (!PyArg_Parse(args, "i", &gid)) + return NULL; + if (setgid(gid) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETGID */ + + +#ifdef HAVE_WAITPID +static char posix_waitpid__doc__[] = +"waitpid(pid, options) -> (pid, status)\n\ +Wait for completion of a give child process."; + +static PyObject * +posix_waitpid(self, args) + PyObject *self; + PyObject *args; +{ + int pid, options; +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "(ii)", &pid, &options)) + return NULL; + Py_BEGIN_ALLOW_THREADS +#ifdef NeXT + pid = wait4(pid, &status, options, NULL); +#else + pid = waitpid(pid, &status, options); +#endif + Py_END_ALLOW_THREADS + if (pid == -1) + return posix_error(); + else + return Py_BuildValue("ii", pid, status_i); +} +#endif /* HAVE_WAITPID */ + + +#ifdef HAVE_WAIT +static char posix_wait__doc__[] = +"wait() -> (pid, status)\n\ +Wait for completion of a child process."; + +static PyObject * +posix_wait(self, args) + PyObject *self; + PyObject *args; +{ + int pid, sts; +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + Py_BEGIN_ALLOW_THREADS + pid = wait(&status); + Py_END_ALLOW_THREADS + if (pid == -1) + return posix_error(); + else + return Py_BuildValue("ii", pid, status_i); +} +#endif + + +static char posix_lstat__doc__[] = +"lstat(path) -> (mode,ino,dev,nlink,uid,gid,size,atime,mtime,ctime)\n\ +Like stat(path), but do not follow symbolic links."; + +static PyObject * +posix_lstat(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef HAVE_LSTAT + return posix_do_stat(self, args, lstat); +#else /* !HAVE_LSTAT */ + return posix_do_stat(self, args, stat); +#endif /* !HAVE_LSTAT */ +} + + +#ifdef HAVE_READLINK +static char posix_readlink__doc__[] = +"readlink(path) -> path\n\ +Return a string representing the path to which the symbolic link points."; + +static PyObject * +posix_readlink(self, args) + PyObject *self; + PyObject *args; +{ + char buf[MAXPATHLEN]; + char *path; + int n; + if (!PyArg_Parse(args, "s", &path)) + return NULL; + Py_BEGIN_ALLOW_THREADS + n = readlink(path, buf, (int) sizeof buf); + Py_END_ALLOW_THREADS + if (n < 0) + return posix_error_with_filename(path); + return PyString_FromStringAndSize(buf, n); +} +#endif /* HAVE_READLINK */ + + +#ifdef HAVE_SYMLINK +static char posix_symlink__doc__[] = +"symlink(src, dst) -> None\n\ +Create a symbolic link."; + +static PyObject * +posix_symlink(self, args) + PyObject *self; + PyObject *args; +{ + return posix_2str(args, symlink); +} +#endif /* HAVE_SYMLINK */ + + +#ifdef HAVE_TIMES +#ifndef HZ +#define HZ 60 /* Universal constant :-) */ +#endif /* HZ */ + +#if defined(PYCC_VACPP) && defined(PYOS_OS2) +static long +system_uptime() +{ + ULONG value = 0; + + Py_BEGIN_ALLOW_THREADS + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &value, sizeof(value)); + Py_END_ALLOW_THREADS + + return value; +} + +static PyObject * +posix_times(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + + /* Currently Only Uptime is Provided -- Others Later */ + return Py_BuildValue("ddddd", + (double)0 /* t.tms_utime / HZ */, + (double)0 /* t.tms_stime / HZ */, + (double)0 /* t.tms_cutime / HZ */, + (double)0 /* t.tms_cstime / HZ */, + (double)system_uptime() / 1000); +} +#else /* not OS2 */ +static PyObject * +posix_times(self, args) + PyObject *self; + PyObject *args; +{ + struct tms t; + clock_t c; + if (!PyArg_NoArgs(args)) + return NULL; + errno = 0; + c = times(&t); + if (c == (clock_t) -1) + return posix_error(); + return Py_BuildValue("ddddd", + (double)t.tms_utime / HZ, + (double)t.tms_stime / HZ, + (double)t.tms_cutime / HZ, + (double)t.tms_cstime / HZ, + (double)c / HZ); +} +#endif /* not OS2 */ +#endif /* HAVE_TIMES */ + + +#ifdef MS_WIN32 +#define HAVE_TIMES /* so the method table will pick it up */ +static PyObject * +posix_times(self, args) + PyObject *self; + PyObject *args; +{ + FILETIME create, exit, kernel, user; + HANDLE hProc; + if (!PyArg_NoArgs(args)) + return NULL; + hProc = GetCurrentProcess(); + GetProcessTimes(hProc, &create, &exit, &kernel, &user); + /* The fields of a FILETIME structure are the hi and lo part + of a 64-bit value expressed in 100 nanosecond units. + 1e7 is one second in such units; 1e-7 the inverse. + 429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7. + */ + return Py_BuildValue( + "ddddd", + (double)(kernel.dwHighDateTime*429.4967296 + + kernel.dwLowDateTime*1e-7), + (double)(user.dwHighDateTime*429.4967296 + + user.dwLowDateTime*1e-7), + (double)0, + (double)0, + (double)0); +} +#endif /* MS_WIN32 */ + +#ifdef HAVE_TIMES +static char posix_times__doc__[] = +"times() -> (utime, stime, cutime, cstime, elapsed_time)\n\ +Return a tuple of floating point numbers indicating process times."; +#endif + + +#ifdef HAVE_SETSID +static char posix_setsid__doc__[] = +"setsid() -> None\n\ +Call the system call setsid()."; + +static PyObject * +posix_setsid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + if (setsid() < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETSID */ + +#ifdef HAVE_SETPGID +static char posix_setpgid__doc__[] = +"setpgid(pid, pgrp) -> None\n\ +Call the system call setpgid()."; + +static PyObject * +posix_setpgid(self, args) + PyObject *self; + PyObject *args; +{ + int pid, pgrp; + if (!PyArg_Parse(args, "(ii)", &pid, &pgrp)) + return NULL; + if (setpgid(pid, pgrp) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETPGID */ + + +#ifdef HAVE_TCGETPGRP +static char posix_tcgetpgrp__doc__[] = +"tcgetpgrp(fd) -> pgid\n\ +Return the process group associated with the terminal given by a fd."; + +static PyObject * +posix_tcgetpgrp(self, args) + PyObject *self; + PyObject *args; +{ + int fd, pgid; + if (!PyArg_Parse(args, "i", &fd)) + return NULL; + pgid = tcgetpgrp(fd); + if (pgid < 0) + return posix_error(); + return PyInt_FromLong((long)pgid); +} +#endif /* HAVE_TCGETPGRP */ + + +#ifdef HAVE_TCSETPGRP +static char posix_tcsetpgrp__doc__[] = +"tcsetpgrp(fd, pgid) -> None\n\ +Set the process group associated with the terminal given by a fd."; + +static PyObject * +posix_tcsetpgrp(self, args) + PyObject *self; + PyObject *args; +{ + int fd, pgid; + if (!PyArg_Parse(args, "(ii)", &fd, &pgid)) + return NULL; + if (tcsetpgrp(fd, pgid) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_TCSETPGRP */ + +/* Functions acting on file descriptors */ + +static char posix_open__doc__[] = +"open(filename, flag [, mode=0777]) -> fd\n\ +Open a file (for low level IO)."; + +static PyObject * +posix_open(self, args) + PyObject *self; + PyObject *args; +{ + char *file; + int flag; + int mode = 0777; + int fd; + if (!PyArg_ParseTuple(args, "si|i", &file, &flag, &mode)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + fd = open(file, flag, mode); + Py_END_ALLOW_THREADS + if (fd < 0) + return posix_error_with_filename(file); + return PyInt_FromLong((long)fd); +} + + +static char posix_close__doc__[] = +"close(fd) -> None\n\ +Close a file descriptor (for low level IO)."; + +static PyObject * +posix_close(self, args) + PyObject *self; + PyObject *args; +{ + int fd, res; + if (!PyArg_Parse(args, "i", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = close(fd); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + + +static char posix_dup__doc__[] = +"dup(fd) -> fd2\n\ +Return a duplicate of a file descriptor."; + +static PyObject * +posix_dup(self, args) + PyObject *self; + PyObject *args; +{ + int fd; + if (!PyArg_Parse(args, "i", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + fd = dup(fd); + Py_END_ALLOW_THREADS + if (fd < 0) + return posix_error(); + return PyInt_FromLong((long)fd); +} + + +static char posix_dup2__doc__[] = +"dup2(fd, fd2) -> None\n\ +Duplicate file descriptor."; + +static PyObject * +posix_dup2(self, args) + PyObject *self; + PyObject *args; +{ + int fd, fd2, res; + if (!PyArg_Parse(args, "(ii)", &fd, &fd2)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = dup2(fd, fd2); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + + +static char posix_lseek__doc__[] = +"lseek(fd, pos, how) -> newpos\n\ +Set the current position of a file descriptor."; + +static PyObject * +posix_lseek(self, args) + PyObject *self; + PyObject *args; +{ + int fd, how; + off_t pos, res; + PyObject *posobj; + if (!PyArg_Parse(args, "(iOi)", &fd, &posobj, &how)) + return NULL; +#ifdef SEEK_SET + /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */ + switch (how) { + case 0: how = SEEK_SET; break; + case 1: how = SEEK_CUR; break; + case 2: how = SEEK_END; break; + } +#endif /* SEEK_END */ + +#if !defined(HAVE_LARGEFILE_SUPPORT) + pos = PyInt_AsLong(posobj); +#else + pos = PyLong_Check(posobj) ? + PyLong_AsLongLong(posobj) : PyInt_AsLong(posobj); +#endif + if (PyErr_Occurred()) + return NULL; + + Py_BEGIN_ALLOW_THREADS + res = lseek(fd, pos, how); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + +#if !defined(HAVE_LARGEFILE_SUPPORT) + return PyInt_FromLong(res); +#else + return PyLong_FromLongLong(res); +#endif +} + + +static char posix_read__doc__[] = +"read(fd, buffersize) -> string\n\ +Read a file descriptor."; + +static PyObject * +posix_read(self, args) + PyObject *self; + PyObject *args; +{ + int fd, size, n; + PyObject *buffer; + if (!PyArg_Parse(args, "(ii)", &fd, &size)) + return NULL; + buffer = PyString_FromStringAndSize((char *)NULL, size); + if (buffer == NULL) + return NULL; + Py_BEGIN_ALLOW_THREADS + n = read(fd, PyString_AsString(buffer), size); + Py_END_ALLOW_THREADS + if (n < 0) { + Py_DECREF(buffer); + return posix_error(); + } + if (n != size) + _PyString_Resize(&buffer, n); + return buffer; +} + + +static char posix_write__doc__[] = +"write(fd, string) -> byteswritten\n\ +Write a string to a file descriptor."; + +static PyObject * +posix_write(self, args) + PyObject *self; + PyObject *args; +{ + int fd, size; + char *buffer; + if (!PyArg_Parse(args, "(is#)", &fd, &buffer, &size)) + return NULL; + Py_BEGIN_ALLOW_THREADS + size = write(fd, buffer, size); + Py_END_ALLOW_THREADS + if (size < 0) + return posix_error(); + return PyInt_FromLong((long)size); +} + + +static char posix_fstat__doc__[]= +"fstat(fd) -> (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\ +Like stat(), but for an open file descriptor."; + +static PyObject * +posix_fstat(self, args) + PyObject *self; + PyObject *args; +{ + int fd; + struct stat st; + int res; + if (!PyArg_Parse(args, "i", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = fstat(fd, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error(); +#if !defined(HAVE_LARGEFILE_SUPPORT) + return Py_BuildValue("(llllllllll)", + (long)st.st_mode, + (long)st.st_ino, + (long)st.st_dev, + (long)st.st_nlink, + (long)st.st_uid, + (long)st.st_gid, + (long)st.st_size, + (long)st.st_atime, + (long)st.st_mtime, + (long)st.st_ctime); +#else + return Py_BuildValue("(lLllllLlll)", + (long)st.st_mode, + (LONG_LONG)st.st_ino, + (long)st.st_dev, + (long)st.st_nlink, + (long)st.st_uid, + (long)st.st_gid, + (LONG_LONG)st.st_size, + (long)st.st_atime, + (long)st.st_mtime, + (long)st.st_ctime); +#endif +} + + +static char posix_fdopen__doc__[] = +"fdopen(fd, [, mode='r' [, bufsize]]) -> file_object\n\ +Return an open file object connected to a file descriptor."; + +static PyObject * +posix_fdopen(self, args) + PyObject *self; + PyObject *args; +{ + extern int fclose Py_PROTO((FILE *)); + int fd; + char *mode = "r"; + int bufsize = -1; + FILE *fp; + PyObject *f; + if (!PyArg_ParseTuple(args, "i|si", &fd, &mode, &bufsize)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + fp = fdopen(fd, mode); + Py_END_ALLOW_THREADS + if (fp == NULL) + return posix_error(); + f = PyFile_FromFile(fp, "(fdopen)", mode, fclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} + + +#ifdef HAVE_PIPE +static char posix_pipe__doc__[] = +"pipe() -> (read_end, write_end)\n\ +Create a pipe."; + +static PyObject * +posix_pipe(self, args) + PyObject *self; + PyObject *args; +{ +#if defined(PYOS_OS2) + HFILE read, write; + APIRET rc; + + if (!PyArg_Parse(args, "")) + return NULL; + + Py_BEGIN_ALLOW_THREADS + rc = DosCreatePipe( &read, &write, 4096); + Py_END_ALLOW_THREADS + if (rc != NO_ERROR) + return os2_error(rc); + + return Py_BuildValue("(ii)", read, write); +#else +#if !defined(MS_WIN32) + int fds[2]; + int res; + if (!PyArg_Parse(args, "")) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = pipe(fds); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error(); + return Py_BuildValue("(ii)", fds[0], fds[1]); +#else /* MS_WIN32 */ + HANDLE read, write; + int read_fd, write_fd; + BOOL ok; + if (!PyArg_Parse(args, "")) + return NULL; + Py_BEGIN_ALLOW_THREADS + ok = CreatePipe(&read, &write, NULL, 0); + Py_END_ALLOW_THREADS + if (!ok) + return posix_error(); + read_fd = _open_osfhandle((long)read, 0); + write_fd = _open_osfhandle((long)write, 1); + return Py_BuildValue("(ii)", read_fd, write_fd); +#endif /* MS_WIN32 */ +#endif +} +#endif /* HAVE_PIPE */ + + +#ifdef HAVE_MKFIFO +static char posix_mkfifo__doc__[] = +"mkfifo(file, [, mode=0666]) -> None\n\ +Create a FIFO (a POSIX named pipe)."; + +static PyObject * +posix_mkfifo(self, args) + PyObject *self; + PyObject *args; +{ + char *file; + int mode = 0666; + int res; + if (!PyArg_ParseTuple(args, "s|i", &file, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = mkfifo(file, mode); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif + + +#ifdef HAVE_FTRUNCATE +static char posix_ftruncate__doc__[] = +"ftruncate(fd, length) -> None\n\ +Truncate a file to a specified length."; + +static PyObject * +posix_ftruncate(self, args) + PyObject *self; /* Not used */ + PyObject *args; +{ + int fd; + off_t length; + int res; + PyObject *lenobj; + + if (!PyArg_Parse(args, "(iO)", &fd, &lenobj)) + return NULL; + +#if !defined(HAVE_LARGEFILE_SUPPORT) + length = PyInt_AsLong(lenobj); +#else + length = PyLong_Check(lenobj) ? + PyLong_AsLongLong(lenobj) : PyInt_AsLong(lenobj); +#endif + if (PyErr_Occurred()) + return NULL; + + Py_BEGIN_ALLOW_THREADS + res = ftruncate(fd, length); + Py_END_ALLOW_THREADS + if (res < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} +#endif + +#ifdef NeXT +#define HAVE_PUTENV +/* Steve Spicklemire got this putenv from NeXTAnswers */ +static int +putenv(char *newval) +{ + extern char **environ; + + static int firstTime = 1; + char **ep; + char *cp; + int esiz; + char *np; + + if (!(np = strchr(newval, '='))) + return 1; + *np = '\0'; + + /* look it up */ + for (ep=environ ; *ep ; ep++) + { + /* this should always be true... */ + if (cp = strchr(*ep, '=')) + { + *cp = '\0'; + if (!strcmp(*ep, newval)) + { + /* got it! */ + *cp = '='; + break; + } + *cp = '='; + } + else + { + *np = '='; + return 1; + } + } + + *np = '='; + if (*ep) + { + /* the string was already there: + just replace it with the new one */ + *ep = newval; + return 0; + } + + /* expand environ by one */ + for (esiz=2, ep=environ ; *ep ; ep++) + esiz++; + if (firstTime) + { + char **epp; + char **newenv; + if (!(newenv = malloc(esiz * sizeof(char *)))) + return 1; + + for (ep=environ, epp=newenv ; *ep ;) + *epp++ = *ep++; + *epp++ = newval; + *epp = (char *) 0; + environ = newenv; + } + else + { + if (!(environ = realloc(environ, esiz * sizeof(char *)))) + return 1; + environ[esiz - 2] = newval; + environ[esiz - 1] = (char *) 0; + firstTime = 0; + } + + return 0; +} +#endif /* NeXT */ + + +#ifdef HAVE_PUTENV +static char posix_putenv__doc__[] = +"putenv(key, value) -> None\n\ +Change or add an environment variable."; + +#ifdef __BEOS__ +/* We have putenv(), but not in the headers (as of PR2). - [cjh] */ +int putenv( const char *str ); +#endif + +static PyObject * +posix_putenv(self, args) + PyObject *self; + PyObject *args; +{ + char *s1, *s2; + char *new; + + if (!PyArg_ParseTuple(args, "ss", &s1, &s2)) + return NULL; + +#if defined(PYOS_OS2) + if (stricmp(s1, "BEGINLIBPATH") == 0) { + APIRET rc; + + if (strlen(s2) == 0) /* If New Value is an Empty String */ + s2 = NULL; /* Then OS/2 API Wants a NULL to Undefine It */ + + rc = DosSetExtLIBPATH(s2, BEGIN_LIBPATH); + if (rc != NO_ERROR) + return os2_error(rc); + + } else if (stricmp(s1, "ENDLIBPATH") == 0) { + APIRET rc; + + if (strlen(s2) == 0) /* If New Value is an Empty String */ + s2 = NULL; /* Then OS/2 API Wants a NULL to Undefine It */ + + rc = DosSetExtLIBPATH(s2, END_LIBPATH); + if (rc != NO_ERROR) + return os2_error(rc); + } else { +#endif + + /* XXX This leaks memory -- not easy to fix :-( */ + if ((new = malloc(strlen(s1) + strlen(s2) + 2)) == NULL) + return PyErr_NoMemory(); + (void) sprintf(new, "%s=%s", s1, s2); + if (putenv(new)) { + posix_error(); + return NULL; + } + +#if defined(PYOS_OS2) + } +#endif + Py_INCREF(Py_None); + return Py_None; +} +#endif /* putenv */ + +#ifdef HAVE_STRERROR +static char posix_strerror__doc__[] = +"strerror(code) -> string\n\ +Translate an error code to a message string."; + +PyObject * +posix_strerror(self, args) + PyObject *self; + PyObject *args; +{ + int code; + char *message; + if (!PyArg_ParseTuple(args, "i", &code)) + return NULL; + message = strerror(code); + if (message == NULL) { + PyErr_SetString(PyExc_ValueError, + "strerror code out of range"); + return NULL; + } + return PyString_FromString(message); +} +#endif /* strerror */ + + +#ifdef HAVE_SYS_WAIT_H + +#ifdef WIFSTOPPED +static char posix_WIFSTOPPED__doc__[] = +"WIFSTOPPED(status) -> Boolean\n\ +Return true if the process returning 'status' was stopped."; + +static PyObject * +posix_WIFSTOPPED(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WIFSTOPPED(status)); +} +#endif /* WIFSTOPPED */ + +#ifdef WIFSIGNALED +static char posix_WIFSIGNALED__doc__[] = +"WIFSIGNALED(status) -> Boolean\n\ +Return true if the process returning 'status' was terminated by a signal."; + +static PyObject * +posix_WIFSIGNALED(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WIFSIGNALED(status)); +} +#endif /* WIFSIGNALED */ + +#ifdef WIFEXITED +static char posix_WIFEXITED__doc__[] = +"WIFEXITED(status) -> Boolean\n\ +Return true if the process returning 'status' exited using the exit()\n\ +system call."; + +static PyObject * +posix_WIFEXITED(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WIFEXITED(status)); +} +#endif /* WIFEXITED */ + +#ifdef WEXITSTATUS +static char posix_WEXITSTATUS__doc__[] = +"WEXITSTATUS(status) -> integer\n\ +Return the process return code from 'status'."; + +static PyObject * +posix_WEXITSTATUS(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WEXITSTATUS(status)); +} +#endif /* WEXITSTATUS */ + +#ifdef WTERMSIG +static char posix_WTERMSIG__doc__[] = +"WTERMSIG(status) -> integer\n\ +Return the signal that terminated the process that provided the 'status'\n\ +value."; + +static PyObject * +posix_WTERMSIG(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WTERMSIG(status)); +} +#endif /* WTERMSIG */ + +#ifdef WSTOPSIG +static char posix_WSTOPSIG__doc__[] = +"WSTOPSIG(status) -> integer\n\ +Return the signal that stopped the process that provided the 'status' value."; + +static PyObject * +posix_WSTOPSIG(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WSTOPSIG(status)); +} +#endif /* WSTOPSIG */ + +#endif /* HAVE_SYS_WAIT_H */ + + +#if defined(HAVE_FSTATVFS) +#include + +static char posix_fstatvfs__doc__[] = +"fstatvfs(fd) -> \n\ + (bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flag, namemax)\n\ +Perform an fstatvfs system call on the given fd."; + +static PyObject * +posix_fstatvfs(self, args) + PyObject *self; + PyObject *args; +{ + int fd, res; + struct statvfs st; + if (!PyArg_ParseTuple(args, "i", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = fstatvfs(fd, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error(); +#if !defined(HAVE_LARGEFILE_SUPPORT) + return Py_BuildValue("(llllllllll)", + (long) st.f_bsize, + (long) st.f_frsize, + (long) st.f_blocks, + (long) st.f_bfree, + (long) st.f_bavail, + (long) st.f_files, + (long) st.f_ffree, + (long) st.f_favail, + (long) st.f_flag, + (long) st.f_namemax); +#else + return Py_BuildValue("(llLLLLLLll)", + (long) st.f_bsize, + (long) st.f_frsize, + (LONG_LONG) st.f_blocks, + (LONG_LONG) st.f_bfree, + (LONG_LONG) st.f_bavail, + (LONG_LONG) st.f_files, + (LONG_LONG) st.f_ffree, + (LONG_LONG) st.f_favail, + (long) st.f_flag, + (long) st.f_namemax); +#endif +} +#endif /* HAVE_FSTATVFS */ + + +#if defined(HAVE_STATVFS) +#include + +static char posix_statvfs__doc__[] = +"statvfs(path) -> \n\ + (bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flag, namemax)\n\ +Perform a statvfs system call on the given path."; + +static PyObject * +posix_statvfs(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + int res; + struct statvfs st; + if (!PyArg_ParseTuple(args, "s", &path)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = statvfs(path, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error_with_filename(path); +#if !defined(HAVE_LARGEFILE_SUPPORT) + return Py_BuildValue("(llllllllll)", + (long) st.f_bsize, + (long) st.f_frsize, + (long) st.f_blocks, + (long) st.f_bfree, + (long) st.f_bavail, + (long) st.f_files, + (long) st.f_ffree, + (long) st.f_favail, + (long) st.f_flag, + (long) st.f_namemax); +#else /* HAVE_LARGEFILE_SUPPORT */ + return Py_BuildValue("(llLLLLLLll)", + (long) st.f_bsize, + (long) st.f_frsize, + (LONG_LONG) st.f_blocks, + (LONG_LONG) st.f_bfree, + (LONG_LONG) st.f_bavail, + (LONG_LONG) st.f_files, + (LONG_LONG) st.f_ffree, + (LONG_LONG) st.f_favail, + (long) st.f_flag, + (long) st.f_namemax); +#endif +} +#endif /* HAVE_STATVFS */ + + +static PyMethodDef posix_methods[] = { + {"access", posix_access, 0, posix_access__doc__}, +#ifdef HAVE_TTYNAME + {"ttyname", posix_ttyname, 0, posix_ttyname__doc__}, +#endif + {"chdir", posix_chdir, 0, posix_chdir__doc__}, + {"chmod", posix_chmod, 0, posix_chmod__doc__}, +#ifdef HAVE_CHOWN + {"chown", posix_chown, 0, posix_chown__doc__}, +#endif /* HAVE_CHOWN */ +#ifdef HAVE_GETCWD + {"getcwd", posix_getcwd, 0, posix_getcwd__doc__}, +#endif +#ifdef HAVE_LINK + {"link", posix_link, 0, posix_link__doc__}, +#endif /* HAVE_LINK */ + {"listdir", posix_listdir, 0, posix_listdir__doc__}, + {"lstat", posix_lstat, 0, posix_lstat__doc__}, + {"mkdir", posix_mkdir, 1, posix_mkdir__doc__}, +#ifdef HAVE_NICE + {"nice", posix_nice, 0, posix_nice__doc__}, +#endif /* HAVE_NICE */ +#ifdef HAVE_READLINK + {"readlink", posix_readlink, 0, posix_readlink__doc__}, +#endif /* HAVE_READLINK */ + {"rename", posix_rename, 0, posix_rename__doc__}, + {"rmdir", posix_rmdir, 0, posix_rmdir__doc__}, + {"stat", posix_stat, 0, posix_stat__doc__}, +#ifdef HAVE_SYMLINK + {"symlink", posix_symlink, 0, posix_symlink__doc__}, +#endif /* HAVE_SYMLINK */ +#ifdef HAVE_SYSTEM + {"system", posix_system, 0, posix_system__doc__}, +#endif + {"umask", posix_umask, 0, posix_umask__doc__}, +#ifdef HAVE_UNAME + {"uname", posix_uname, 0, posix_uname__doc__}, +#endif /* HAVE_UNAME */ + {"unlink", posix_unlink, 0, posix_unlink__doc__}, + {"remove", posix_unlink, 0, posix_remove__doc__}, + {"utime", posix_utime, 0, posix_utime__doc__}, +#ifdef HAVE_TIMES + {"times", posix_times, 0, posix_times__doc__}, +#endif /* HAVE_TIMES */ + {"_exit", posix__exit, 0, posix__exit__doc__}, +#ifdef HAVE_EXECV + {"execv", posix_execv, 0, posix_execv__doc__}, + {"execve", posix_execve, 0, posix_execve__doc__}, +#endif /* HAVE_EXECV */ +#ifdef HAVE_SPAWNV + {"spawnv", posix_spawnv, 0, posix_spawnv__doc__}, + {"spawnve", posix_spawnve, 0, posix_spawnve__doc__}, +#endif /* HAVE_SPAWNV */ +#ifdef HAVE_FORK + {"fork", posix_fork, 0, posix_fork__doc__}, +#endif /* HAVE_FORK */ +#ifdef HAVE_GETEGID + {"getegid", posix_getegid, 0, posix_getegid__doc__}, +#endif /* HAVE_GETEGID */ +#ifdef HAVE_GETEUID + {"geteuid", posix_geteuid, 0, posix_geteuid__doc__}, +#endif /* HAVE_GETEUID */ +#ifdef HAVE_GETGID + {"getgid", posix_getgid, 0, posix_getgid__doc__}, +#endif /* HAVE_GETGID */ + {"getpid", posix_getpid, 0, posix_getpid__doc__}, +#ifdef HAVE_GETPGRP + {"getpgrp", posix_getpgrp, 0, posix_getpgrp__doc__}, +#endif /* HAVE_GETPGRP */ +#ifdef HAVE_GETPPID + {"getppid", posix_getppid, 0, posix_getppid__doc__}, +#endif /* HAVE_GETPPID */ +#ifdef HAVE_GETUID + {"getuid", posix_getuid, 0, posix_getuid__doc__}, +#endif /* HAVE_GETUID */ +#ifdef HAVE_KILL + {"kill", posix_kill, 0, posix_kill__doc__}, +#endif /* HAVE_KILL */ +#ifdef HAVE_PLOCK + {"plock", posix_plock, 0, posix_plock__doc__}, +#endif /* HAVE_PLOCK */ +#ifdef HAVE_POPEN + {"popen", posix_popen, 1, posix_popen__doc__}, +#endif /* HAVE_POPEN */ +#ifdef HAVE_SETUID + {"setuid", posix_setuid, 0, posix_setuid__doc__}, +#endif /* HAVE_SETUID */ +#ifdef HAVE_SETGID + {"setgid", posix_setgid, 0, posix_setgid__doc__}, +#endif /* HAVE_SETGID */ +#ifdef HAVE_SETPGRP + {"setpgrp", posix_setpgrp, 0, posix_setpgrp__doc__}, +#endif /* HAVE_SETPGRP */ +#ifdef HAVE_WAIT + {"wait", posix_wait, 0, posix_wait__doc__}, +#endif /* HAVE_WAIT */ +#ifdef HAVE_WAITPID + {"waitpid", posix_waitpid, 0, posix_waitpid__doc__}, +#endif /* HAVE_WAITPID */ +#ifdef HAVE_SETSID + {"setsid", posix_setsid, 0, posix_setsid__doc__}, +#endif /* HAVE_SETSID */ +#ifdef HAVE_SETPGID + {"setpgid", posix_setpgid, 0, posix_setpgid__doc__}, +#endif /* HAVE_SETPGID */ +#ifdef HAVE_TCGETPGRP + {"tcgetpgrp", posix_tcgetpgrp, 0, posix_tcgetpgrp__doc__}, +#endif /* HAVE_TCGETPGRP */ +#ifdef HAVE_TCSETPGRP + {"tcsetpgrp", posix_tcsetpgrp, 0, posix_tcsetpgrp__doc__}, +#endif /* HAVE_TCSETPGRP */ + {"open", posix_open, 1, posix_open__doc__}, + {"close", posix_close, 0, posix_close__doc__}, + {"dup", posix_dup, 0, posix_dup__doc__}, + {"dup2", posix_dup2, 0, posix_dup2__doc__}, + {"lseek", posix_lseek, 0, posix_lseek__doc__}, + {"read", posix_read, 0, posix_read__doc__}, + {"write", posix_write, 0, posix_write__doc__}, + {"fstat", posix_fstat, 0, posix_fstat__doc__}, + {"fdopen", posix_fdopen, 1, posix_fdopen__doc__}, +#ifdef HAVE_PIPE + {"pipe", posix_pipe, 0, posix_pipe__doc__}, +#endif +#ifdef HAVE_MKFIFO + {"mkfifo", posix_mkfifo, 1, posix_mkfifo__doc__}, +#endif +#ifdef HAVE_FTRUNCATE + {"ftruncate", posix_ftruncate, 1, posix_ftruncate__doc__}, +#endif +#ifdef HAVE_PUTENV + {"putenv", posix_putenv, 1, posix_putenv__doc__}, +#endif +#ifdef HAVE_STRERROR + {"strerror", posix_strerror, 1, posix_strerror__doc__}, +#endif +#ifdef HAVE_FSYNC + {"fsync", posix_fsync, 0, posix_fsync__doc__}, +#endif +#ifdef HAVE_FDATASYNC + {"fdatasync", posix_fdatasync, 0, posix_fdatasync__doc__}, +#endif +#ifdef HAVE_SYS_WAIT_H +#ifdef WIFSTOPPED + {"WIFSTOPPED", posix_WIFSTOPPED, 0, posix_WIFSTOPPED__doc__}, +#endif /* WIFSTOPPED */ +#ifdef WIFSIGNALED + {"WIFSIGNALED", posix_WIFSIGNALED, 0, posix_WIFSIGNALED__doc__}, +#endif /* WIFSIGNALED */ +#ifdef WIFEXITED + {"WIFEXITED", posix_WIFEXITED, 0, posix_WIFEXITED__doc__}, +#endif /* WIFEXITED */ +#ifdef WEXITSTATUS + {"WEXITSTATUS", posix_WEXITSTATUS, 0, posix_WEXITSTATUS__doc__}, +#endif /* WEXITSTATUS */ +#ifdef WTERMSIG + {"WTERMSIG", posix_WTERMSIG, 0, posix_WTERMSIG__doc__}, +#endif /* WTERMSIG */ +#ifdef WSTOPSIG + {"WSTOPSIG", posix_WSTOPSIG, 0, posix_WSTOPSIG__doc__}, +#endif /* WSTOPSIG */ +#endif /* HAVE_SYS_WAIT_H */ +#ifdef HAVE_FSTATVFS + {"fstatvfs", posix_fstatvfs, 1, posix_fstatvfs__doc__}, +#endif +#ifdef HAVE_STATVFS + {"statvfs", posix_statvfs, 1, posix_statvfs__doc__}, +#endif + {NULL, NULL} /* Sentinel */ +}; + + +static int +ins(d, symbol, value) + PyObject* d; + char* symbol; + long value; +{ + PyObject* v = PyInt_FromLong(value); + if (!v || PyDict_SetItemString(d, symbol, v) < 0) + return -1; /* triggers fatal error */ + + Py_DECREF(v); + return 0; +} + +#if defined(PYOS_OS2) +/* Insert Platform-Specific Constant Values (Strings & Numbers) of Common Use */ +static int insertvalues(PyObject *d) +{ + APIRET rc; + ULONG values[QSV_MAX+1]; + PyObject *v; + char *ver, tmp[10]; + + Py_BEGIN_ALLOW_THREADS + rc = DosQuerySysInfo(1, QSV_MAX, &values[1], sizeof(values)); + Py_END_ALLOW_THREADS + + if (rc != NO_ERROR) { + os2_error(rc); + return -1; + } + + if (ins(d, "meminstalled", values[QSV_TOTPHYSMEM])) return -1; + if (ins(d, "memkernel", values[QSV_TOTRESMEM])) return -1; + if (ins(d, "memvirtual", values[QSV_TOTAVAILMEM])) return -1; + if (ins(d, "maxpathlen", values[QSV_MAX_PATH_LENGTH])) return -1; + if (ins(d, "maxnamelen", values[QSV_MAX_COMP_LENGTH])) return -1; + if (ins(d, "revision", values[QSV_VERSION_REVISION])) return -1; + if (ins(d, "timeslice", values[QSV_MIN_SLICE])) return -1; + + switch (values[QSV_VERSION_MINOR]) { + case 0: ver = "2.00"; break; + case 10: ver = "2.10"; break; + case 11: ver = "2.11"; break; + case 30: ver = "3.00"; break; + case 40: ver = "4.00"; break; + case 50: ver = "5.00"; break; + default: + sprintf(tmp, "%d-%d", values[QSV_VERSION_MAJOR], + values[QSV_VERSION_MINOR]); + ver = &tmp[0]; + } + + /* Add Indicator of the Version of the Operating System */ + v = PyString_FromString(ver); + if (!v || PyDict_SetItemString(d, "version", v) < 0) + return -1; + Py_DECREF(v); + + /* Add Indicator of Which Drive was Used to Boot the System */ + tmp[0] = 'A' + values[QSV_BOOT_DRIVE] - 1; + tmp[1] = ':'; + tmp[2] = '\0'; + + v = PyString_FromString(tmp); + if (!v || PyDict_SetItemString(d, "bootdrive", v) < 0) + return -1; + Py_DECREF(v); + + return 0; +} +#endif + +static int +all_ins(d) + PyObject* d; +{ +#ifdef F_OK + if (ins(d, "F_OK", (long)F_OK)) return -1; +#endif +#ifdef R_OK + if (ins(d, "R_OK", (long)R_OK)) return -1; +#endif +#ifdef W_OK + if (ins(d, "W_OK", (long)W_OK)) return -1; +#endif +#ifdef X_OK + if (ins(d, "X_OK", (long)X_OK)) return -1; +#endif +#ifdef WNOHANG + if (ins(d, "WNOHANG", (long)WNOHANG)) return -1; +#endif +#ifdef O_RDONLY + if (ins(d, "O_RDONLY", (long)O_RDONLY)) return -1; +#endif +#ifdef O_WRONLY + if (ins(d, "O_WRONLY", (long)O_WRONLY)) return -1; +#endif +#ifdef O_RDWR + if (ins(d, "O_RDWR", (long)O_RDWR)) return -1; +#endif +#ifdef O_NDELAY + if (ins(d, "O_NDELAY", (long)O_NDELAY)) return -1; +#endif +#ifdef O_NONBLOCK + if (ins(d, "O_NONBLOCK", (long)O_NONBLOCK)) return -1; +#endif +#ifdef O_APPEND + if (ins(d, "O_APPEND", (long)O_APPEND)) return -1; +#endif +#ifdef O_DSYNC + if (ins(d, "O_DSYNC", (long)O_DSYNC)) return -1; +#endif +#ifdef O_RSYNC + if (ins(d, "O_RSYNC", (long)O_RSYNC)) return -1; +#endif +#ifdef O_SYNC + if (ins(d, "O_SYNC", (long)O_SYNC)) return -1; +#endif +#ifdef O_NOCTTY + if (ins(d, "O_NOCTTY", (long)O_NOCTTY)) return -1; +#endif +#ifdef O_CREAT + if (ins(d, "O_CREAT", (long)O_CREAT)) return -1; +#endif +#ifdef O_EXCL + if (ins(d, "O_EXCL", (long)O_EXCL)) return -1; +#endif +#ifdef O_TRUNC + if (ins(d, "O_TRUNC", (long)O_TRUNC)) return -1; +#endif +#ifdef O_BINARY + if (ins(d, "O_BINARY", (long)O_BINARY)) return -1; +#endif +#ifdef O_TEXT + if (ins(d, "O_TEXT", (long)O_TEXT)) return -1; +#endif + +#ifdef HAVE_SPAWNV + if (ins(d, "P_WAIT", (long)_P_WAIT)) return -1; + if (ins(d, "P_NOWAIT", (long)_P_NOWAIT)) return -1; + if (ins(d, "P_OVERLAY", (long)_OLD_P_OVERLAY)) return -1; + if (ins(d, "P_NOWAITO", (long)_P_NOWAITO)) return -1; + if (ins(d, "P_DETACH", (long)_P_DETACH)) return -1; +#endif + +#if defined(PYOS_OS2) + if (insertvalues(d)) return -1; +#endif + return 0; +} + + +#if ( defined(_MSC_VER) || defined(__WATCOMC__) ) && !defined(__QNX__) +#define INITFUNC initnt +#define MODNAME "nt" +#else +#if defined(PYOS_OS2) +#define INITFUNC initos2 +#define MODNAME "os2" +#else +#define INITFUNC initposix +#define MODNAME "posix" +#endif +#endif + +DL_EXPORT(void) +INITFUNC() +{ + PyObject *m, *d, *v; + + m = Py_InitModule4(MODNAME, + posix_methods, + posix__doc__, + (PyObject *)NULL, + PYTHON_API_VERSION); + d = PyModule_GetDict(m); + + /* Initialize environ dictionary */ + v = convertenviron(); + if (v == NULL || PyDict_SetItemString(d, "environ", v) != 0) + return; + Py_DECREF(v); + + if (all_ins(d)) + return; + + PyDict_SetItemString(d, "error", PyExc_OSError); +} diff --git a/src/main/resource/testFiles/cpython/prevFiles/prev_df0d00_1254d7_Python#ceval.c b/src/main/resource/testFiles/cpython/prevFiles/prev_df0d00_1254d7_Python#ceval.c new file mode 100644 index 0000000..032b14d --- /dev/null +++ b/src/main/resource/testFiles/cpython/prevFiles/prev_df0d00_1254d7_Python#ceval.c @@ -0,0 +1,2740 @@ +/*********************************************************** +Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, +The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI or Corporation for National Research Initiatives or +CNRI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +While CWI is the initial source for this software, a modified version +is made available by the Corporation for National Research Initiatives +(CNRI) at the Internet address ftp://ftp.python.org. + +STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH +CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Execute compiled code */ + +/* XXX TO DO: + XXX how to pass arguments to call_trace? + XXX speed up searching for keywords by using a dictionary + XXX document it! + */ + +#include "Python.h" + +#include "compile.h" +#include "frameobject.h" +#include "eval.h" +#include "opcode.h" + +#include + +#ifdef HAVE_LIMITS_H +#include +#else +#define INT_MAX 2147483647 +#endif + +/* Turn this on if your compiler chokes on the big switch: */ +/* #define CASE_TOO_BIG 1 */ + +#ifdef Py_DEBUG +/* For debugging the interpreter: */ +#define LLTRACE 1 /* Low-level trace feature */ +#define CHECKEXC 1 /* Double-check exception checking */ +#endif + + +/* Forward declarations */ + +static PyObject *eval_code2 Py_PROTO((PyCodeObject *, + PyObject *, PyObject *, + PyObject **, int, + PyObject **, int, + PyObject **, int, + PyObject *)); +#ifdef LLTRACE +static int prtrace Py_PROTO((PyObject *, char *)); +#endif +static void call_exc_trace Py_PROTO((PyObject **, PyObject**, + PyFrameObject *)); +static int call_trace Py_PROTO((PyObject **, PyObject **, + PyFrameObject *, char *, PyObject *)); +static PyObject *call_builtin Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *call_function Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *loop_subscript Py_PROTO((PyObject *, PyObject *)); +static int slice_index Py_PROTO((PyObject *, int *)); +static PyObject *apply_slice Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int assign_slice Py_PROTO((PyObject *, PyObject *, + PyObject *, PyObject *)); +static int cmp_exception Py_PROTO((PyObject *, PyObject *)); +static int cmp_member Py_PROTO((PyObject *, PyObject *)); +static PyObject *cmp_outcome Py_PROTO((int, PyObject *, PyObject *)); +static int import_from Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *build_class Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int exec_statement Py_PROTO((PyFrameObject *, + PyObject *, PyObject *, PyObject *)); +static PyObject *find_from_args Py_PROTO((PyFrameObject *, int)); +static void set_exc_info Py_PROTO((PyThreadState *, + PyObject *, PyObject *, PyObject *)); +static void reset_exc_info Py_PROTO((PyThreadState *)); + + +/* Dynamic execution profile */ +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS +static long dxpairs[257][256]; +#define dxp dxpairs[256] +#else +static long dxp[256]; +#endif +#endif + + +#ifdef WITH_THREAD + +#include +#include "thread.h" + +extern int _PyThread_Started; /* Flag for Py_Exit */ + +static type_lock interpreter_lock = 0; +static long main_thread = 0; + +void +PyEval_InitThreads() +{ + if (interpreter_lock) + return; + _PyThread_Started = 1; + interpreter_lock = allocate_lock(); + acquire_lock(interpreter_lock, 1); + main_thread = get_thread_ident(); +} + +#endif + +/* Functions save_thread and restore_thread are always defined so + dynamically loaded modules needn't be compiled separately for use + with and without threads: */ + +PyObject * +PyEval_SaveThread() +{ +#ifdef WITH_THREAD + if (interpreter_lock) { + PyThreadState *tstate = PyThreadState_Swap(NULL); + PyObject *res = tstate ? (PyObject *) (tstate->frame) : NULL; + release_lock(interpreter_lock); + return res; + } +#endif + return NULL; +} + +void +PyEval_RestoreThread(x) + PyObject *x; +{ +#ifdef WITH_THREAD + if (interpreter_lock) { + int err; + err = errno; + acquire_lock(interpreter_lock, 1); + errno = err; + PyThreadState_Swap(x ? ((PyFrameObject *)x)->f_tstate : NULL); + } +#endif +} + + +/* Mechanism whereby asynchronously executing callbacks (e.g. UNIX + signal handlers or Mac I/O completion routines) can schedule calls + to a function to be called synchronously. + The synchronous function is called with one void* argument. + It should return 0 for success or -1 for failure -- failure should + be accompanied by an exception. + + If registry succeeds, the registry function returns 0; if it fails + (e.g. due to too many pending calls) it returns -1 (without setting + an exception condition). + + Note that because registry may occur from within signal handlers, + or other asynchronous events, calling malloc() is unsafe! + +#ifdef WITH_THREAD + Any thread can schedule pending calls, but only the main thread + will execute them. +#endif + + XXX WARNING! ASYNCHRONOUSLY EXECUTING CODE! + There are two possible race conditions: + (1) nested asynchronous registry calls; + (2) registry calls made while pending calls are being processed. + While (1) is very unlikely, (2) is a real possibility. + The current code is safe against (2), but not against (1). + The safety against (2) is derived from the fact that only one + thread (the main thread) ever takes things out of the queue. + + XXX Darn! With the advent of thread state, we should have an array + of pending calls per thread in the thread state! Later... +*/ + +#define NPENDINGCALLS 32 +static struct { + int (*func) Py_PROTO((ANY *)); + ANY *arg; +} pendingcalls[NPENDINGCALLS]; +static volatile int pendingfirst = 0; +static volatile int pendinglast = 0; +static volatile int things_to_do = 0; + +int +Py_AddPendingCall(func, arg) + int (*func) Py_PROTO((ANY *)); + ANY *arg; +{ + static int busy = 0; + int i, j; + /* XXX Begin critical section */ + /* XXX If you want this to be safe against nested + XXX asynchronous calls, you'll have to work harder! */ + if (busy) + return -1; + busy = 1; + i = pendinglast; + j = (i + 1) % NPENDINGCALLS; + if (j == pendingfirst) + return -1; /* Queue full */ + pendingcalls[i].func = func; + pendingcalls[i].arg = arg; + pendinglast = j; + things_to_do = 1; /* Signal main loop */ + busy = 0; + /* XXX End critical section */ + return 0; +} + +int +Py_MakePendingCalls() +{ + static int busy = 0; +#ifdef WITH_THREAD + if (main_thread && get_thread_ident() != main_thread) + return 0; +#endif + if (busy) + return 0; + busy = 1; + things_to_do = 0; + for (;;) { + int i; + int (*func) Py_PROTO((ANY *)); + ANY *arg; + i = pendingfirst; + if (i == pendinglast) + break; /* Queue empty */ + func = pendingcalls[i].func; + arg = pendingcalls[i].arg; + pendingfirst = (i + 1) % NPENDINGCALLS; + if (func(arg) < 0) { + busy = 0; + things_to_do = 1; /* We're not done yet */ + return -1; + } + } + busy = 0; + return 0; +} + + +/* Status code for main loop (reason for stack unwind) */ + +enum why_code { + WHY_NOT, /* No error */ + WHY_EXCEPTION, /* Exception occurred */ + WHY_RERAISE, /* Exception re-raised by 'finally' */ + WHY_RETURN, /* 'return' statement */ + WHY_BREAK /* 'break' statement */ +}; + +static enum why_code do_raise Py_PROTO((PyObject *, PyObject *, PyObject *)); + + +/* Backward compatible interface */ + +PyObject * +PyEval_EvalCode(co, globals, locals) + PyCodeObject *co; + PyObject *globals; + PyObject *locals; +{ + return eval_code2(co, + globals, locals, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + (PyObject *)NULL); +} + + +/* Interpreter main loop */ + +#ifndef MAX_RECURSION_DEPTH +#define MAX_RECURSION_DEPTH 10000 +#endif + +static PyObject * +eval_code2(co, globals, locals, + args, argcount, kws, kwcount, defs, defcount, owner) + PyCodeObject *co; + PyObject *globals; + PyObject *locals; + PyObject **args; + int argcount; + PyObject **kws; /* length: 2*kwcount */ + int kwcount; + PyObject **defs; + int defcount; + PyObject *owner; +{ +#ifdef DXPAIRS + int lastopcode = 0; +#endif + register unsigned char *next_instr; + register int opcode = 0; /* Current opcode */ + register int oparg = 0; /* Current opcode argument, if any */ + register PyObject **stack_pointer; + register enum why_code why; /* Reason for block stack unwind */ + register int err; /* Error status -- nonzero if error */ + register PyObject *x; /* Result object -- NULL if error */ + register PyObject *v; /* Temporary objects popped off stack */ + register PyObject *w; + register PyObject *u; + register PyObject *t; + register PyFrameObject *f; /* Current frame */ + register PyObject **fastlocals = NULL; + PyObject *retval = NULL; /* Return value */ + PyThreadState *tstate = PyThreadState_Get(); +#ifdef LLTRACE + int lltrace; +#endif +#if defined(Py_DEBUG) || defined(LLTRACE) + /* Make it easier to find out where we are with a debugger */ + char *filename = PyString_AsString(co->co_filename); +#endif + +/* Code access macros */ + +#define GETCONST(i) Getconst(f, i) +#define GETNAME(i) Getname(f, i) +#define GETNAMEV(i) Getnamev(f, i) +#define FIRST_INSTR() (GETUSTRINGVALUE(co->co_code)) +#define INSTR_OFFSET() (next_instr - FIRST_INSTR()) +#define NEXTOP() (*next_instr++) +#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) +#define JUMPTO(x) (next_instr = FIRST_INSTR() + (x)) +#define JUMPBY(x) (next_instr += (x)) + +/* Stack manipulation macros */ + +#define STACK_LEVEL() (stack_pointer - f->f_valuestack) +#define EMPTY() (STACK_LEVEL() == 0) +#define TOP() (stack_pointer[-1]) +#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +#define BASIC_POP() (*--stack_pointer) + +#ifdef LLTRACE +#define PUSH(v) (BASIC_PUSH(v), lltrace && prtrace(TOP(), "push")) +#define POP() (lltrace && prtrace(TOP(), "pop"), BASIC_POP()) +#else +#define PUSH(v) BASIC_PUSH(v) +#define POP() BASIC_POP() +#endif + +/* Local variable macros */ + +#define GETLOCAL(i) (fastlocals[i]) +#define SETLOCAL(i, value) do { Py_XDECREF(GETLOCAL(i)); \ + GETLOCAL(i) = value; } while (0) + +/* Start of code */ + + if (tstate == NULL) + Py_FatalError("eval_code2 called without a current thread"); + +#ifdef USE_STACKCHECK + if (tstate->recursion_depth%10 == 0 && PyOS_CheckStack()) { + PyErr_SetString(PyExc_MemoryError, "Stack overflow"); + return NULL; + } +#endif + + if (globals == NULL) { + PyErr_SetString(PyExc_SystemError, "eval_code2: NULL globals"); + return NULL; + } + +#ifdef LLTRACE + lltrace = PyDict_GetItemString(globals, "__lltrace__") != NULL; +#endif + + f = PyFrame_New( + tstate, /*back*/ + co, /*code*/ + globals, /*globals*/ + locals); /*locals*/ + if (f == NULL) + return NULL; + + tstate->frame = f; + fastlocals = f->f_localsplus; + + if (co->co_argcount > 0 || + co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { + int i; + int n = argcount; + PyObject *kwdict = NULL; + if (co->co_flags & CO_VARKEYWORDS) { + kwdict = PyDict_New(); + if (kwdict == NULL) + goto fail; + i = co->co_argcount; + if (co->co_flags & CO_VARARGS) + i++; + SETLOCAL(i, kwdict); + } + if (argcount > co->co_argcount) { + if (!(co->co_flags & CO_VARARGS)) { + PyErr_SetString(PyExc_TypeError, + "too many arguments"); + goto fail; + } + n = co->co_argcount; + } + for (i = 0; i < n; i++) { + x = args[i]; + Py_INCREF(x); + SETLOCAL(i, x); + } + if (co->co_flags & CO_VARARGS) { + u = PyTuple_New(argcount - n); + if (u == NULL) + goto fail; + SETLOCAL(co->co_argcount, u); + for (i = n; i < argcount; i++) { + x = args[i]; + Py_INCREF(x); + PyTuple_SET_ITEM(u, i-n, x); + } + } + for (i = 0; i < kwcount; i++) { + PyObject *keyword = kws[2*i]; + PyObject *value = kws[2*i + 1]; + int j; + /* XXX slow -- speed up using dictionary? */ + for (j = 0; j < co->co_argcount; j++) { + PyObject *nm = PyTuple_GET_ITEM( + co->co_varnames, j); + if (PyObject_Compare(keyword, nm) == 0) + break; + } + if (j >= co->co_argcount) { + if (kwdict == NULL) { + PyErr_Format(PyExc_TypeError, + "unexpected keyword argument: %.400s", + PyString_AsString(keyword)); + goto fail; + } + PyDict_SetItem(kwdict, keyword, value); + } + else { + if (GETLOCAL(j) != NULL) { + PyErr_SetString(PyExc_TypeError, + "keyword parameter redefined"); + goto fail; + } + Py_INCREF(value); + SETLOCAL(j, value); + } + } + if (argcount < co->co_argcount) { + int m = co->co_argcount - defcount; + for (i = argcount; i < m; i++) { + if (GETLOCAL(i) == NULL) { + PyErr_SetString(PyExc_TypeError, + "not enough arguments"); + goto fail; + } + } + if (n > m) + i = n - m; + else + i = 0; + for (; i < defcount; i++) { + if (GETLOCAL(m+i) == NULL) { + PyObject *def = defs[i]; + Py_INCREF(def); + SETLOCAL(m+i, def); + } + } + } + } + else { + if (argcount > 0 || kwcount > 0) { + PyErr_SetString(PyExc_TypeError, + "no arguments expected"); + goto fail; + } + } + + if (tstate->sys_tracefunc != NULL) { + /* tstate->sys_tracefunc, if defined, is a function that + will be called on *every* entry to a code block. + Its return value, if not None, is a function that + will be called at the start of each executed line + of code. (Actually, the function must return + itself in order to continue tracing.) + The trace functions are called with three arguments: + a pointer to the current frame, a string indicating + why the function is called, and an argument which + depends on the situation. The global trace function + (sys.trace) is also called whenever an exception + is detected. */ + if (call_trace(&tstate->sys_tracefunc, + &f->f_trace, f, "call", + Py_None/*XXX how to compute arguments now?*/)) { + /* Trace function raised an error */ + goto fail; + } + } + + if (tstate->sys_profilefunc != NULL) { + /* Similar for sys_profilefunc, except it needn't return + itself and isn't called for "line" events */ + if (call_trace(&tstate->sys_profilefunc, + (PyObject**)0, f, "call", + Py_None/*XXX*/)) { + goto fail; + } + } + + if (++tstate->recursion_depth > MAX_RECURSION_DEPTH) { + --tstate->recursion_depth; + PyErr_SetString(PyExc_RuntimeError, + "Maximum recursion depth exceeded"); + tstate->frame = f->f_back; + Py_DECREF(f); + return NULL; + } + + next_instr = GETUSTRINGVALUE(co->co_code); + stack_pointer = f->f_valuestack; + + why = WHY_NOT; + err = 0; + x = Py_None; /* Not a reference, just anything non-NULL */ + + for (;;) { + /* Do periodic things. Doing this every time through + the loop would add too much overhead, so we do it + only every Nth instruction. We also do it if + ``things_to_do'' is set, i.e. when an asynchronous + event needs attention (e.g. a signal handler or + async I/O handler); see Py_AddPendingCall() and + Py_MakePendingCalls() above. */ + + if (things_to_do || --tstate->ticker < 0) { + tstate->ticker = tstate->sys_checkinterval; + if (things_to_do) { + if (Py_MakePendingCalls() < 0) { + why = WHY_EXCEPTION; + goto on_error; + } + } +#if !defined(HAVE_SIGNAL_H) && !defined(macintosh) + /* If we have true signals, the signal handler + will call Py_AddPendingCall() so we don't + have to call sigcheck(). On the Mac and + DOS, alas, we have to call it. */ + if (PyErr_CheckSignals()) { + why = WHY_EXCEPTION; + goto on_error; + } +#endif + +#ifdef WITH_THREAD + if (interpreter_lock) { + /* Give another thread a chance */ + + PyThreadState *tstate = + PyThreadState_Swap(NULL); + release_lock(interpreter_lock); + + /* Other threads may run now */ + + acquire_lock(interpreter_lock, 1); + PyThreadState_Swap(tstate); + } +#endif + } + + /* Extract opcode and argument */ + +#if defined(Py_DEBUG) || defined(LLTRACE) + f->f_lasti = INSTR_OFFSET(); +#endif + + opcode = NEXTOP(); + if (HAS_ARG(opcode)) + oparg = NEXTARG(); +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS + dxpairs[lastopcode][opcode]++; + lastopcode = opcode; +#endif + dxp[opcode]++; +#endif + +#ifdef LLTRACE + /* Instruction tracing */ + + if (lltrace) { + if (HAS_ARG(opcode)) { + printf("%d: %d, %d\n", + (int) (INSTR_OFFSET() - 3), + opcode, oparg); + } + else { + printf("%d: %d\n", + (int) (INSTR_OFFSET() - 1), opcode); + } + } +#endif + + /* Main switch on opcode */ + + switch (opcode) { + + /* BEWARE! + It is essential that any operation that fails sets either + x to NULL, err to nonzero, or why to anything but WHY_NOT, + and that no operation that succeeds does this! */ + + /* case STOP_CODE: this is an error! */ + + case POP_TOP: + v = POP(); + Py_DECREF(v); + continue; + + case ROT_TWO: + v = POP(); + w = POP(); + PUSH(v); + PUSH(w); + continue; + + case ROT_THREE: + v = POP(); + w = POP(); + x = POP(); + PUSH(v); + PUSH(x); + PUSH(w); + continue; + + case DUP_TOP: + v = TOP(); + Py_INCREF(v); + PUSH(v); + continue; + + case UNARY_POSITIVE: + v = POP(); + x = PyNumber_Positive(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_NEGATIVE: + v = POP(); + x = PyNumber_Negative(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_NOT: + v = POP(); + err = PyObject_IsTrue(v); + Py_DECREF(v); + if (err == 0) { + Py_INCREF(Py_True); + PUSH(Py_True); + continue; + } + else if (err > 0) { + Py_INCREF(Py_False); + PUSH(Py_False); + err = 0; + continue; + } + break; + + case UNARY_CONVERT: + v = POP(); + x = PyObject_Repr(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_INVERT: + v = POP(); + x = PyNumber_Invert(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_POWER: + w = POP(); + v = POP(); + x = PyNumber_Power(v, w, Py_None); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_MULTIPLY: + w = POP(); + v = POP(); + x = PyNumber_Multiply(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_DIVIDE: + w = POP(); + v = POP(); + x = PyNumber_Divide(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_MODULO: + w = POP(); + v = POP(); + x = PyNumber_Remainder(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_ADD: + w = POP(); + v = POP(); + x = PyNumber_Add(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_SUBTRACT: + w = POP(); + v = POP(); + x = PyNumber_Subtract(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_SUBSCR: + w = POP(); + v = POP(); + x = PyObject_GetItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_LSHIFT: + w = POP(); + v = POP(); + x = PyNumber_Lshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_RSHIFT: + w = POP(); + v = POP(); + x = PyNumber_Rshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_AND: + w = POP(); + v = POP(); + x = PyNumber_And(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_XOR: + w = POP(); + v = POP(); + x = PyNumber_Xor(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_OR: + w = POP(); + v = POP(); + x = PyNumber_Or(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case SLICE+0: + case SLICE+1: + case SLICE+2: + case SLICE+3: + if ((opcode-SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + x = apply_slice(u, v, w); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case STORE_SLICE+0: + case STORE_SLICE+1: + case STORE_SLICE+2: + case STORE_SLICE+3: + if ((opcode-STORE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-STORE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + t = POP(); + err = assign_slice(u, v, w, t); /* u[v:w] = t */ + Py_DECREF(t); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case DELETE_SLICE+0: + case DELETE_SLICE+1: + case DELETE_SLICE+2: + case DELETE_SLICE+3: + if ((opcode-DELETE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-DELETE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + err = assign_slice(u, v, w, (PyObject *)NULL); + /* del u[v:w] */ + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case STORE_SUBSCR: + w = POP(); + v = POP(); + u = POP(); + /* v[w] = u */ + err = PyObject_SetItem(v, w, u); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case DELETE_SUBSCR: + w = POP(); + v = POP(); + /* del v[w] */ + err = PyObject_DelItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case PRINT_EXPR: + v = POP(); + /* Print value except if procedure result */ + /* Before printing, also assign to '_' */ + if (v != Py_None && + (err = PyDict_SetItemString( + f->f_builtins, "_", v)) == 0 && + !Py_SuppressPrintingFlag) { + Py_FlushLine(); + x = PySys_GetObject("stdout"); + err = PyFile_WriteObject(v, x, 0); + PyFile_SoftSpace(x, 1); + Py_FlushLine(); + } + Py_DECREF(v); + break; + + case PRINT_ITEM: + v = POP(); + w = PySys_GetObject("stdout"); + if (PyFile_SoftSpace(w, 1)) + PyFile_WriteString(" ", w); + err = PyFile_WriteObject(v, w, Py_PRINT_RAW); + if (err == 0 && PyString_Check(v)) { + /* XXX move into writeobject() ? */ + char *s = PyString_AsString(v); + int len = PyString_Size(v); + if (len > 0 && + isspace(Py_CHARMASK(s[len-1])) && + s[len-1] != ' ') + PyFile_SoftSpace(w, 0); + } + Py_DECREF(v); + if (err == 0) continue; + break; + + case PRINT_NEWLINE: + x = PySys_GetObject("stdout"); + if (x == NULL) + PyErr_SetString(PyExc_RuntimeError, + "lost sys.stdout"); + else { + PyFile_WriteString("\n", x); + PyFile_SoftSpace(x, 0); + } + break; + + case BREAK_LOOP: + why = WHY_BREAK; + break; + + case RAISE_VARARGS: + u = v = w = NULL; + switch (oparg) { + case 3: + u = POP(); /* traceback */ + /* Fallthrough */ + case 2: + v = POP(); /* value */ + /* Fallthrough */ + case 1: + w = POP(); /* exc */ + why = do_raise(w, v, u); + break; + default: + PyErr_SetString(PyExc_SystemError, + "bad RAISE_VARARGS oparg"); + why = WHY_EXCEPTION; + break; + } + break; + + case LOAD_LOCALS: + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + Py_INCREF(x); + PUSH(x); + break; + + case RETURN_VALUE: + retval = POP(); + why = WHY_RETURN; + break; + + case EXEC_STMT: + w = POP(); + v = POP(); + u = POP(); + err = exec_statement(f, u, v, w); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case POP_BLOCK: + { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_DECREF(v); + } + } + break; + + case END_FINALLY: + v = POP(); + if (PyInt_Check(v)) { + why = (enum why_code) PyInt_AsLong(v); + if (why == WHY_RETURN) + retval = POP(); + } + else if (PyString_Check(v) || PyClass_Check(v)) { + w = POP(); + u = POP(); + PyErr_Restore(v, w, u); + why = WHY_RERAISE; + break; + } + else if (v != Py_None) { + PyErr_SetString(PyExc_SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; + } + Py_DECREF(v); + break; + + case BUILD_CLASS: + u = POP(); + v = POP(); + w = POP(); + x = build_class(u, v, w); + PUSH(x); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case STORE_NAME: + w = GETNAMEV(oparg); + v = POP(); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + err = PyDict_SetItem(x, w, v); + Py_DECREF(v); + break; + + case DELETE_NAME: + w = GETNAMEV(oparg); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + if ((err = PyDict_DelItem(x, w)) != 0) + PyErr_SetObject(PyExc_NameError, w); + break; + +#ifdef CASE_TOO_BIG + default: switch (opcode) { +#endif + + case UNPACK_TUPLE: + v = POP(); + if (!PyTuple_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "unpack non-tuple"); + why = WHY_EXCEPTION; + } + else if (PyTuple_Size(v) != oparg) { + PyErr_SetString(PyExc_ValueError, + "unpack tuple of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = PyTuple_GET_ITEM(v, oparg); + Py_INCREF(w); + PUSH(w); + } + } + Py_DECREF(v); + break; + + case UNPACK_LIST: + v = POP(); + if (!PyList_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "unpack non-list"); + why = WHY_EXCEPTION; + } + else if (PyList_Size(v) != oparg) { + PyErr_SetString(PyExc_ValueError, + "unpack list of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = PyList_GetItem(v, oparg); + Py_INCREF(w); + PUSH(w); + } + } + Py_DECREF(v); + break; + + case STORE_ATTR: + w = GETNAMEV(oparg); + v = POP(); + u = POP(); + err = PyObject_SetAttr(v, w, u); /* v.w = u */ + Py_DECREF(v); + Py_DECREF(u); + break; + + case DELETE_ATTR: + w = GETNAMEV(oparg); + v = POP(); + err = PyObject_SetAttr(v, w, (PyObject *)NULL); + /* del v.w */ + Py_DECREF(v); + break; + + case STORE_GLOBAL: + w = GETNAMEV(oparg); + v = POP(); + err = PyDict_SetItem(f->f_globals, w, v); + Py_DECREF(v); + break; + + case DELETE_GLOBAL: + w = GETNAMEV(oparg); + if ((err = PyDict_DelItem(f->f_globals, w)) != 0) + PyErr_SetObject(PyExc_NameError, w); + break; + + case LOAD_CONST: + x = GETCONST(oparg); + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_NAME: + w = GETNAMEV(oparg); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + x = PyDict_GetItem(x, w); + if (x == NULL) { + PyErr_Clear(); + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + PyErr_Clear(); + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + PyErr_SetObject( + PyExc_NameError, w); + break; + } + } + } + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_GLOBAL: + w = GETNAMEV(oparg); + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + PyErr_Clear(); + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + PyErr_SetObject(PyExc_NameError, w); + break; + } + } + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_FAST: + x = GETLOCAL(oparg); + if (x == NULL) { + PyErr_SetObject(PyExc_NameError, + PyTuple_GetItem(co->co_varnames, + oparg)); + break; + } + Py_INCREF(x); + PUSH(x); + if (x != NULL) continue; + break; + + case STORE_FAST: + v = POP(); + SETLOCAL(oparg, v); + continue; + + case DELETE_FAST: + SETLOCAL(oparg, NULL); + continue; + + case BUILD_TUPLE: + x = PyTuple_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + PyTuple_SET_ITEM(x, oparg, w); + } + PUSH(x); + continue; + } + break; + + case BUILD_LIST: + x = PyList_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + err = PyList_SetItem(x, oparg, w); + if (err != 0) + break; + } + PUSH(x); + continue; + } + break; + + case BUILD_MAP: + x = PyDict_New(); + PUSH(x); + if (x != NULL) continue; + break; + + case LOAD_ATTR: + w = GETNAMEV(oparg); + v = POP(); + x = PyObject_GetAttr(v, w); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case COMPARE_OP: + w = POP(); + v = POP(); + x = cmp_outcome(oparg, v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case IMPORT_NAME: + w = GETNAMEV(oparg); + x = PyDict_GetItemString(f->f_builtins, "__import__"); + if (x == NULL) { + PyErr_SetString(PyExc_ImportError, + "__import__ not found"); + break; + } + if (PyCFunction_Check(x)) { + u = Py_None; + Py_INCREF(u); + } + else { + u = find_from_args(f, INSTR_OFFSET()); + if (u == NULL) { + x = u; + break; + } + } + w = Py_BuildValue("(OOOO)", + w, + f->f_globals, + f->f_locals == NULL ? + Py_None : f->f_locals, + u); + Py_DECREF(u); + if (w == NULL) { + x = NULL; + break; + } + x = PyEval_CallObject(x, w); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case IMPORT_FROM: + w = GETNAMEV(oparg); + v = TOP(); + PyFrame_FastToLocals(f); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + err = import_from(x, v, w); + PyFrame_LocalsToFast(f, 0); + if (err == 0) continue; + break; + + case JUMP_FORWARD: + JUMPBY(oparg); + continue; + + case JUMP_IF_FALSE: + err = PyObject_IsTrue(TOP()); + if (err > 0) + err = 0; + else if (err == 0) + JUMPBY(oparg); + else + break; + continue; + + case JUMP_IF_TRUE: + err = PyObject_IsTrue(TOP()); + if (err > 0) { + err = 0; + JUMPBY(oparg); + } + else if (err == 0) + ; + else + break; + continue; + + case JUMP_ABSOLUTE: + JUMPTO(oparg); + continue; + + case FOR_LOOP: + /* for v in s: ... + On entry: stack contains s, i. + On exit: stack contains s, i+1, s[i]; + but if loop exhausted: + s, i are popped, and we jump */ + w = POP(); /* Loop index */ + v = POP(); /* Sequence object */ + u = loop_subscript(v, w); + if (u != NULL) { + PUSH(v); + x = PyInt_FromLong(PyInt_AsLong(w)+1); + PUSH(x); + Py_DECREF(w); + PUSH(u); + if (x != NULL) continue; + } + else { + Py_DECREF(v); + Py_DECREF(w); + /* A NULL can mean "s exhausted" + but also an error: */ + if (PyErr_Occurred()) + why = WHY_EXCEPTION; + else { + JUMPBY(oparg); + continue; + } + } + break; + + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); + continue; + + case SET_LINENO: +#ifdef LLTRACE + if (lltrace) + printf("--- %s:%d \n", filename, oparg); +#endif + f->f_lineno = oparg; + if (f->f_trace == NULL) + continue; + /* Trace each line of code reached */ + f->f_lasti = INSTR_OFFSET(); + err = call_trace(&f->f_trace, &f->f_trace, + f, "line", Py_None); + break; + + case CALL_FUNCTION: + { + int na = oparg & 0xff; + int nk = (oparg>>8) & 0xff; + int n = na + 2*nk; + PyObject **pfunc = stack_pointer - n - 1; + PyObject *func = *pfunc; + PyObject *self = NULL; + PyObject *class = NULL; + f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */ + if (PyMethod_Check(func)) { + self = PyMethod_Self(func); + class = PyMethod_Class(func); + func = PyMethod_Function(func); + Py_INCREF(func); + if (self != NULL) { + Py_INCREF(self); + Py_DECREF(*pfunc); + *pfunc = self; + na++; + n++; + } + else { + /* Unbound methods must be + called with an instance of + the class (or a derived + class) as first argument */ + if (na > 0 && + (self = stack_pointer[-n]) + != NULL && + PyInstance_Check(self) && + PyClass_IsSubclass( + (PyObject *) + (((PyInstanceObject *)self) + ->in_class), + class)) + /* Handy-dandy */ ; + else { + PyErr_SetString( + PyExc_TypeError, + "unbound method must be called with class instance 1st argument"); + x = NULL; + break; + } + } + } + else + Py_INCREF(func); + if (PyFunction_Check(func)) { + PyObject *co = PyFunction_GetCode(func); + PyObject *globals = + PyFunction_GetGlobals(func); + PyObject *argdefs = + PyFunction_GetDefaults(func); + PyObject **d; + int nd; + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = ((PyTupleObject *)argdefs) -> + ob_size; + } + else { + d = NULL; + nd = 0; + } + x = eval_code2( + (PyCodeObject *)co, + globals, (PyObject *)NULL, + stack_pointer-n, na, + stack_pointer-2*nk, nk, + d, nd, + class); + } + else { + PyObject *args = PyTuple_New(na); + PyObject *kwdict = NULL; + if (args == NULL) { + x = NULL; + break; + } + if (nk > 0) { + kwdict = PyDict_New(); + if (kwdict == NULL) { + x = NULL; + break; + } + err = 0; + while (--nk >= 0) { + PyObject *value = POP(); + PyObject *key = POP(); + err = PyDict_SetItem( + kwdict, key, value); + Py_DECREF(key); + Py_DECREF(value); + if (err) + break; + } + if (err) { + Py_DECREF(args); + Py_DECREF(kwdict); + break; + } + } + while (--na >= 0) { + w = POP(); + PyTuple_SET_ITEM(args, na, w); + } + x = PyEval_CallObjectWithKeywords( + func, args, kwdict); + Py_DECREF(args); + Py_XDECREF(kwdict); + } + Py_DECREF(func); + while (stack_pointer > pfunc) { + w = POP(); + Py_DECREF(w); + } + PUSH(x); + if (x != NULL) continue; + break; + } + + case MAKE_FUNCTION: + v = POP(); /* code object */ + x = PyFunction_New(v, f->f_globals); + Py_DECREF(v); + /* XXX Maybe this should be a separate opcode? */ + if (x != NULL && oparg > 0) { + v = PyTuple_New(oparg); + if (v == NULL) { + Py_DECREF(x); + x = NULL; + break; + } + while (--oparg >= 0) { + w = POP(); + PyTuple_SET_ITEM(v, oparg, w); + } + err = PyFunction_SetDefaults(x, v); + Py_DECREF(v); + } + PUSH(x); + break; + + case BUILD_SLICE: + if (oparg == 3) + w = POP(); + else + w = NULL; + v = POP(); + u = POP(); + x = PySlice_New(u, v, w); + Py_DECREF(u); + Py_DECREF(v); + Py_XDECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + + default: + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + f->f_lineno, opcode); + PyErr_SetString(PyExc_SystemError, "unknown opcode"); + why = WHY_EXCEPTION; + break; + +#ifdef CASE_TOO_BIG + } +#endif + + } /* switch */ + + on_error: + + /* Quickly continue if no error occurred */ + + if (why == WHY_NOT) { + if (err == 0 && x != NULL) { +#ifdef CHECKEXC + if (PyErr_Occurred()) + fprintf(stderr, + "XXX undetected error\n"); + else +#endif + continue; /* Normal, fast path */ + } + why = WHY_EXCEPTION; + x = Py_None; + err = 0; + } + +#ifdef CHECKEXC + /* Double-check exception status */ + + if (why == WHY_EXCEPTION || why == WHY_RERAISE) { + if (!PyErr_Occurred()) { + fprintf(stderr, "XXX ghost error\n"); + PyErr_SetString(PyExc_SystemError, + "ghost error"); + why = WHY_EXCEPTION; + } + } + else { + if (PyErr_Occurred()) { + fprintf(stderr, + "XXX undetected error (why=%d)\n", + why); + why = WHY_EXCEPTION; + } + } +#endif + + /* Log traceback info if this is a real exception */ + + if (why == WHY_EXCEPTION) { + f->f_lasti = INSTR_OFFSET() - 1; + if (HAS_ARG(opcode)) + f->f_lasti -= 2; + PyTraceBack_Here(f); + + if (f->f_trace) + call_exc_trace(&f->f_trace, &f->f_trace, f); + if (tstate->sys_profilefunc) + call_exc_trace(&tstate->sys_profilefunc, + (PyObject**)0, f); +} + + /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ + + if (why == WHY_RERAISE) + why = WHY_EXCEPTION; + + /* Unwind stacks if a (pseudo) exception occurred */ + + while (why != WHY_NOT && f->f_iblock > 0) { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_XDECREF(v); + } + if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + if (b->b_type == SETUP_FINALLY || + (b->b_type == SETUP_EXCEPT && + why == WHY_EXCEPTION)) { + if (why == WHY_EXCEPTION) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (val == NULL) { + val = Py_None; + Py_INCREF(val); + } + /* Make the raw exception data + available to the handler, + so a program can emulate the + Python main loop. Don't do + this for 'finally'. */ + if (b->b_type == SETUP_EXCEPT) { + set_exc_info(tstate, + exc, val, tb); + } + PUSH(tb); + PUSH(val); + PUSH(exc); + } + else { + if (why == WHY_RETURN) + PUSH(retval); + v = PyInt_FromLong((long)why); + PUSH(v); + } + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + } /* unwind stack */ + + /* End the loop if we still have an error (or return) */ + + if (why != WHY_NOT) + break; + + } /* main loop */ + + /* Pop remaining stack entries */ + + while (!EMPTY()) { + v = POP(); + Py_XDECREF(v); + } + + if (why != WHY_RETURN) + retval = NULL; + + if (f->f_trace) { + if (why == WHY_RETURN) { + if (call_trace(&f->f_trace, &f->f_trace, f, + "return", retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + } + + if (tstate->sys_profilefunc && why == WHY_RETURN) { + if (call_trace(&tstate->sys_profilefunc, (PyObject**)0, + f, "return", retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + + reset_exc_info(tstate); + + --tstate->recursion_depth; + + fail: /* Jump here from prelude on failure */ + + /* Restore previous frame and release the current one */ + + tstate->frame = f->f_back; + Py_DECREF(f); + + return retval; +} + +static void +set_exc_info(tstate, type, value, tb) + PyThreadState *tstate; + PyObject *type; + PyObject *value; + PyObject *tb; +{ + PyFrameObject *frame; + frame = tstate->frame; + if (frame->f_exc_type == NULL) { + /* This frame didn't catch an exception before */ + /* Save previous exception of this thread in this frame */ + Py_XDECREF(frame->f_exc_type); + Py_XDECREF(frame->f_exc_value); + Py_XDECREF(frame->f_exc_traceback); + if (tstate->exc_type == NULL) { + Py_INCREF(Py_None); + tstate->exc_type = Py_None; + } + Py_XINCREF(tstate->exc_type); + Py_XINCREF(tstate->exc_value); + Py_XINCREF(tstate->exc_traceback); + frame->f_exc_type = tstate->exc_type; + frame->f_exc_value = tstate->exc_value; + frame->f_exc_traceback = tstate->exc_traceback; + } + /* Set new exception for this thread */ + Py_XINCREF(type); + Py_XINCREF(value); + Py_XINCREF(tb); + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + /* For b/w compatibility */ + PySys_SetObject("exc_type", type); + PySys_SetObject("exc_value", value); + PySys_SetObject("exc_traceback", tb); +} + +static void +reset_exc_info(tstate) + PyThreadState *tstate; +{ + PyFrameObject *frame; + frame = tstate->frame; + if (frame->f_exc_type != NULL) { + /* This frame caught an exception */ + Py_XDECREF(tstate->exc_type); + Py_XDECREF(tstate->exc_value); + Py_XDECREF(tstate->exc_traceback); + Py_XINCREF(frame->f_exc_type); + Py_XINCREF(frame->f_exc_value); + Py_XINCREF(frame->f_exc_traceback); + tstate->exc_type = frame->f_exc_type; + tstate->exc_value = frame->f_exc_value; + tstate->exc_traceback = frame->f_exc_traceback; + /* For b/w compatibility */ + PySys_SetObject("exc_type", frame->f_exc_type); + PySys_SetObject("exc_value", frame->f_exc_value); + PySys_SetObject("exc_traceback", frame->f_exc_traceback); + } + Py_XDECREF(frame->f_exc_type); + Py_XDECREF(frame->f_exc_value); + Py_XDECREF(frame->f_exc_traceback); + frame->f_exc_type = NULL; + frame->f_exc_value = NULL; + frame->f_exc_traceback = NULL; +} + +/* Logic for the raise statement (too complicated for inlining). + This *consumes* a reference count to each of its arguments. */ +static enum why_code +do_raise(type, value, tb) + PyObject *type, *value, *tb; +{ + /* We support the following forms of raise: + raise , + raise , + raise , None + raise , + raise , None + raise , + raise , None + + An omitted second argument is the same as None. + + In addition, raise , is the same as + raising the tuple's first item (and it better have one!); + this rule is applied recursively. + + Finally, an optional third argument can be supplied, which + gives the traceback to be substituted (useful when + re-raising an exception after examining it). */ + + /* First, check the traceback argument, replacing None with + NULL. */ + if (tb == Py_None) { + Py_DECREF(tb); + tb = NULL; + } + else if (tb != NULL && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise 3rd arg must be traceback or None"); + goto raise_error; + } + + /* Next, replace a missing value with None */ + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + + /* Next, repeatedly, replace a tuple exception with its first item */ + while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { + PyObject *tmp = type; + type = PyTuple_GET_ITEM(type, 0); + Py_INCREF(type); + Py_DECREF(tmp); + } + + /* Now switch on the exception's type */ + if (PyString_Check(type)) { + ; + } + else if (PyClass_Check(type)) { + /* Raising a class. If the value is an instance, it + better be an instance of the class. If it is not, + it will be used to create an instance. */ + if (PyInstance_Check(value)) { + PyObject *inclass = (PyObject*) + (((PyInstanceObject*)value)->in_class); + if (!PyClass_IsSubclass(inclass, type)) { + PyErr_SetString(PyExc_TypeError, + "raise , requires that is a member of "); + goto raise_error; + } + } + else { + /* Go instantiate the class */ + PyObject *args, *res; + if (value == Py_None) + args = Py_BuildValue("()"); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } + else + args = Py_BuildValue("(O)", value); + if (args == NULL) + goto raise_error; + res = PyEval_CallObject(type, args); + Py_DECREF(args); + if (res == NULL) + goto raise_error; + Py_DECREF(value); + value = res; + } + } + else if (PyInstance_Check(type)) { + /* Raising an instance. The value should be a dummy. */ + if (value != Py_None) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + else { + /* Normalize to raise , */ + Py_DECREF(value); + value = type; + type = (PyObject*) ((PyInstanceObject*)type)->in_class; + Py_INCREF(type); + } + } + else { + /* Not something you can raise. You get an exception + anyway, just not what you specified :-) */ + PyErr_SetString(PyExc_TypeError, + "exceptions must be strings, classes, or instances"); + goto raise_error; + } + PyErr_Restore(type, value, tb); + if (tb == NULL) + return WHY_EXCEPTION; + else + return WHY_RERAISE; + raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return WHY_EXCEPTION; +} + +#ifdef LLTRACE +static int +prtrace(v, str) + PyObject *v; + char *str; +{ + printf("%s ", str); + if (PyObject_Print(v, stdout, 0) != 0) + PyErr_Clear(); /* Don't know what else to do */ + printf("\n"); +} +#endif + +static void +call_exc_trace(p_trace, p_newtrace, f) + PyObject **p_trace, **p_newtrace; + PyFrameObject *f; +{ + PyObject *type, *value, *traceback, *arg; + int err; + PyErr_Fetch(&type, &value, &traceback); + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + arg = Py_BuildValue("(OOO)", type, value, traceback); + if (arg == NULL) { + PyErr_Restore(type, value, traceback); + return; + } + err = call_trace(p_trace, p_newtrace, f, "exception", arg); + Py_DECREF(arg); + if (err == 0) + PyErr_Restore(type, value, traceback); + else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } +} + +static int +call_trace(p_trace, p_newtrace, f, msg, arg) + PyObject **p_trace; /* in/out; may not be NULL; + may not point to NULL variable initially */ + PyObject **p_newtrace; /* in/out; may be NULL; + may point to NULL variable; + may be same variable as p_newtrace */ + PyFrameObject *f; + char *msg; + PyObject *arg; +{ + PyThreadState *tstate = f->f_tstate; + PyObject *args, *what; + PyObject *res = NULL; + + if (tstate->tracing) { + /* Don't do recursive traces */ + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + *p_newtrace = NULL; + } + return 0; + } + + args = PyTuple_New(3); + if (args == NULL) + goto Py_Cleanup; + what = PyString_FromString(msg); + if (what == NULL) + goto Py_Cleanup; + Py_INCREF(f); + PyTuple_SET_ITEM(args, 0, (PyObject *)f); + PyTuple_SET_ITEM(args, 1, what); + if (arg == NULL) + arg = Py_None; + Py_INCREF(arg); + PyTuple_SET_ITEM(args, 2, arg); + tstate->tracing++; + PyFrame_FastToLocals(f); + res = PyEval_CallObject(*p_trace, args); /* May clear *p_trace! */ + PyFrame_LocalsToFast(f, 1); + tstate->tracing--; + Py_Cleanup: + Py_XDECREF(args); + if (res == NULL) { + /* The trace proc raised an exception */ + PyTraceBack_Here(f); + Py_XDECREF(*p_trace); + *p_trace = NULL; + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + *p_newtrace = NULL; + } + return -1; + } + else { + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + if (res == Py_None) + *p_newtrace = NULL; + else { + Py_INCREF(res); + *p_newtrace = res; + } + } + Py_DECREF(res); + return 0; + } +} + +PyObject * +PyEval_GetBuiltins() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + if (current_frame == NULL) + return PyBuiltin_GetModule(); + else + return current_frame->f_builtins; +} + +PyObject * +PyEval_GetLocals() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + if (current_frame == NULL) + return NULL; + PyFrame_FastToLocals(current_frame); + return current_frame->f_locals; +} + +PyObject * +PyEval_GetGlobals() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + if (current_frame == NULL) + return NULL; + else + return current_frame->f_globals; +} + +PyObject * +PyEval_GetFrame() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + return (PyObject *)current_frame; +} + +int +PyEval_GetRestricted() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + return current_frame == NULL ? 0 : current_frame->f_restricted; +} + +void +Py_FlushLine() +{ + PyObject *f = PySys_GetObject("stdout"); + if (PyFile_SoftSpace(f, 0)) + PyFile_WriteString("\n", f); +} + + +/* External interface to call any callable object. + The arg must be a tuple or NULL. */ + +PyObject * +PyEval_CallObject(func, arg) + PyObject *func; + PyObject *arg; +{ + return PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL); +} + +PyObject * +PyEval_CallObjectWithKeywords(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + ternaryfunc call; + PyObject *result; + + if (arg == NULL) + arg = PyTuple_New(0); + else if (!PyTuple_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "argument list must be a tuple"); + return NULL; + } + else + Py_INCREF(arg); + + if (kw != NULL && !PyDict_Check(kw)) { + PyErr_SetString(PyExc_TypeError, + "keyword list must be a dictionary"); + return NULL; + } + + if ((call = func->ob_type->tp_call) != NULL) + result = (*call)(func, arg, kw); + else if (PyMethod_Check(func) || PyFunction_Check(func)) + result = call_function(func, arg, kw); + else + result = call_builtin(func, arg, kw); + + Py_DECREF(arg); + + if (result == NULL && !PyErr_Occurred()) + PyErr_SetString(PyExc_SystemError, + "NULL result without error in call_object"); + + return result; +} + +static PyObject * +call_builtin(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + if (PyCFunction_Check(func)) { + PyCFunction meth = PyCFunction_GetFunction(func); + PyObject *self = PyCFunction_GetSelf(func); + int flags = PyCFunction_GetFlags(func); + if (!(flags & METH_VARARGS)) { + int size = PyTuple_Size(arg); + if (size == 1) + arg = PyTuple_GET_ITEM(arg, 0); + else if (size == 0) + arg = NULL; + } + if (flags & METH_KEYWORDS) + return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); + if (kw != NULL && PyDict_Size(kw) != 0) { + PyErr_SetString(PyExc_TypeError, + "this function takes no keyword arguments"); + return NULL; + } + return (*meth)(self, arg); + } + if (PyClass_Check(func)) { + return PyInstance_New(func, arg, kw); + } + if (PyInstance_Check(func)) { + PyObject *res, *call = PyObject_GetAttrString(func,"__call__"); + if (call == NULL) { + PyErr_Clear(); + PyErr_SetString(PyExc_AttributeError, + "no __call__ method defined"); + return NULL; + } + res = PyEval_CallObjectWithKeywords(call, arg, kw); + Py_DECREF(call); + return res; + } + PyErr_SetString(PyExc_TypeError, "call of non-function"); + return NULL; +} + +static PyObject * +call_function(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + PyObject *class = NULL; /* == owner */ + PyObject *argdefs; + PyObject **d, **k; + int nk, nd; + PyObject *result; + + if (kw != NULL && !PyDict_Check(kw)) { + PyErr_BadInternalCall(); + return NULL; + } + + if (PyMethod_Check(func)) { + PyObject *self = PyMethod_Self(func); + class = PyMethod_Class(func); + func = PyMethod_Function(func); + if (self == NULL) { + /* Unbound methods must be called with an instance of + the class (or a derived class) as first argument */ + if (PyTuple_Size(arg) >= 1) { + self = PyTuple_GET_ITEM(arg, 0); + if (self != NULL && + PyInstance_Check(self) && + PyClass_IsSubclass((PyObject *) + (((PyInstanceObject *)self)->in_class), + class)) + /* Handy-dandy */ ; + else + self = NULL; + } + if (self == NULL) { + PyErr_SetString(PyExc_TypeError, + "unbound method must be called with class instance 1st argument"); + return NULL; + } + Py_INCREF(arg); + } + else { + int argcount = PyTuple_Size(arg); + PyObject *newarg = PyTuple_New(argcount + 1); + int i; + if (newarg == NULL) + return NULL; + Py_INCREF(self); + PyTuple_SET_ITEM(newarg, 0, self); + for (i = 0; i < argcount; i++) { + PyObject *v = PyTuple_GET_ITEM(arg, i); + Py_XINCREF(v); + PyTuple_SET_ITEM(newarg, i+1, v); + } + arg = newarg; + } + } + else { + if (!PyFunction_Check(func)) { + PyErr_SetString(PyExc_TypeError, + "call of non-function"); + return NULL; + } + Py_INCREF(arg); + } + + argdefs = PyFunction_GetDefaults(func); + if (argdefs != NULL && PyTuple_Check(argdefs)) { + d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0); + nd = PyTuple_Size(argdefs); + } + else { + d = NULL; + nd = 0; + } + + if (kw != NULL) { + int pos, i; + nk = PyDict_Size(kw); + k = PyMem_NEW(PyObject *, 2*nk); + if (k == NULL) { + PyErr_NoMemory(); + Py_DECREF(arg); + return NULL; + } + pos = i = 0; + while (PyDict_Next(kw, &pos, &k[i], &k[i+1])) + i += 2; + nk = i/2; + /* XXX This is broken if the caller deletes dict items! */ + } + else { + k = NULL; + nk = 0; + } + + result = eval_code2( + (PyCodeObject *)PyFunction_GetCode(func), + PyFunction_GetGlobals(func), (PyObject *)NULL, + &PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg), + k, nk, + d, nd, + class); + + Py_DECREF(arg); + PyMem_XDEL(k); + + return result; +} + +#define SLICE_ERROR_MSG \ + "standard sequence type does not support step size other than one" + +static PyObject * +loop_subscript(v, w) + PyObject *v, *w; +{ + PySequenceMethods *sq = v->ob_type->tp_as_sequence; + int i; + if (sq == NULL) { + PyErr_SetString(PyExc_TypeError, "loop over non-sequence"); + return NULL; + } + i = PyInt_AsLong(w); + v = (*sq->sq_item)(v, i); + if (v) + return v; + if (PyErr_Occurred() == PyExc_IndexError) + PyErr_Clear(); + return NULL; +} + +static int +slice_index(v, pi) + PyObject *v; + int *pi; +{ + if (v != NULL) { + long x; + if (!PyInt_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "slice index must be int"); + return -1; + } + x = PyInt_AsLong(v); + /* Truncate -- very long indices are truncated anyway */ + if (x > INT_MAX) + x = INT_MAX; + else if (x < -INT_MAX) + x = 0; + *pi = x; + } + return 0; +} + +static PyObject * +apply_slice(u, v, w) /* return u[v:w] */ + PyObject *u, *v, *w; +{ + int ilow = 0, ihigh = INT_MAX; + if (slice_index(v, &ilow) != 0) + return NULL; + if (slice_index(w, &ihigh) != 0) + return NULL; + return PySequence_GetSlice(u, ilow, ihigh); +} + +static int +assign_slice(u, v, w, x) /* u[v:w] = x */ + PyObject *u, *v, *w, *x; +{ + int ilow = 0, ihigh = INT_MAX; + if (slice_index(v, &ilow) != 0) + return -1; + if (slice_index(w, &ihigh) != 0) + return -1; + if (x == NULL) + return PySequence_DelSlice(u, ilow, ihigh); + else + return PySequence_SetSlice(u, ilow, ihigh, x); +} + +static int +cmp_exception(err, v) + PyObject *err, *v; +{ + if (PyTuple_Check(v)) { + int i, n; + n = PyTuple_Size(v); + for (i = 0; i < n; i++) { + /* Test recursively */ + if (cmp_exception(err, PyTuple_GET_ITEM(v, i))) + return 1; + } + return 0; + } + if (PyClass_Check(v) && PyClass_Check(err)) + return PyClass_IsSubclass(err, v); + return err == v; +} + +static int +cmp_member(v, w) + PyObject *v, *w; +{ + int i, cmp; + PyObject *x; + PySequenceMethods *sq; + /* Special case for char in string */ + if (PyString_Check(w)) { + register char *s, *end; + register char c; + if (!PyString_Check(v) || PyString_Size(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "string member test needs char left operand"); + return -1; + } + c = PyString_AsString(v)[0]; + s = PyString_AsString(w); + end = s + PyString_Size(w); + while (s < end) { + if (c == *s++) + return 1; + } + return 0; + } + sq = w->ob_type->tp_as_sequence; + if (sq == NULL) { + PyErr_SetString(PyExc_TypeError, + "'in' or 'not in' needs sequence right argument"); + return -1; + } + for (i = 0; ; i++) { + x = (*sq->sq_item)(w, i); + if (x == NULL) { + if (PyErr_Occurred() == PyExc_IndexError) { + PyErr_Clear(); + break; + } + return -1; + } + cmp = PyObject_Compare(v, x); + Py_XDECREF(x); + if (cmp == 0) + return 1; + } + return 0; +} + +static PyObject * +cmp_outcome(op, v, w) + int op; + register PyObject *v; + register PyObject *w; +{ + register int cmp; + register int res = 0; + switch (op) { + case IS: + case IS_NOT: + res = (v == w); + if (op == (int) IS_NOT) + res = !res; + break; + case IN: + case NOT_IN: + res = cmp_member(v, w); + if (res < 0) + return NULL; + if (op == (int) NOT_IN) + res = !res; + break; + case EXC_MATCH: + res = cmp_exception(v, w); + break; + default: + cmp = PyObject_Compare(v, w); + switch (op) { + case LT: res = cmp < 0; break; + case LE: res = cmp <= 0; break; + case EQ: res = cmp == 0; break; + case NE: res = cmp != 0; break; + case GT: res = cmp > 0; break; + case GE: res = cmp >= 0; break; + /* XXX no default? (res is initialized to 0 though) */ + } + } + v = res ? Py_True : Py_False; + Py_INCREF(v); + return v; +} + +static int +import_from(locals, v, name) + PyObject *locals; + PyObject *v; + PyObject *name; +{ + PyObject *w, *x; + if (!PyModule_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "import-from requires module object"); + return -1; + } + w = PyModule_GetDict(v); + if (PyString_AsString(name)[0] == '*') { + int pos, err; + PyObject *name, *value; + pos = 0; + while (PyDict_Next(w, &pos, &name, &value)) { + if (!PyString_Check(name) || + PyString_AsString(name)[0] == '_') + continue; + Py_INCREF(value); + err = PyDict_SetItem(locals, name, value); + Py_DECREF(value); + if (err != 0) + return -1; + } + return 0; + } + else { + x = PyDict_GetItem(w, name); + if (x == NULL) { + char buf[250]; + sprintf(buf, "cannot import name %.230s", + PyString_AsString(name)); + PyErr_SetString(PyExc_ImportError, buf); + return -1; + } + else + return PyDict_SetItem(locals, name, x); + } +} + +static PyObject * +build_class(methods, bases, name) + PyObject *methods; /* dictionary */ + PyObject *bases; /* tuple containing classes */ + PyObject *name; /* string */ +{ + int i; + if (!PyTuple_Check(bases)) { + PyErr_SetString(PyExc_SystemError, + "build_class with non-tuple bases"); + return NULL; + } + if (!PyDict_Check(methods)) { + PyErr_SetString(PyExc_SystemError, + "build_class with non-dictionary"); + return NULL; + } + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_SystemError, + "build_class witn non-string name"); + return NULL; + } + for (i = PyTuple_Size(bases); --i >= 0; ) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + if (!PyClass_Check(base)) { + /* Call the base's *type*, if it is callable. + This code is a hook for Donald Beaudry's + and Jim Fulton's type extensions. In + unexended Python it will never be triggered + since its types are not callable. */ + if (base->ob_type->ob_type->tp_call) { + PyObject *args; + PyObject *class; + args = Py_BuildValue("(OOO)", + name, bases, methods); + class = PyEval_CallObject( + (PyObject *)base->ob_type, args); + Py_DECREF(args); + return class; + } + PyErr_SetString(PyExc_TypeError, + "base is not a class object"); + return NULL; + } + } + return PyClass_New(bases, methods, name); +} + +static int +exec_statement(f, prog, globals, locals) + PyFrameObject *f; + PyObject *prog; + PyObject *globals; + PyObject *locals; +{ + char *s; + int n; + PyObject *v; + int plain = 0; + + if (PyTuple_Check(prog) && globals == Py_None && locals == Py_None && + ((n = PyTuple_Size(prog)) == 2 || n == 3)) { + /* Backward compatibility hack */ + globals = PyTuple_GetItem(prog, 1); + if (n == 3) + locals = PyTuple_GetItem(prog, 2); + prog = PyTuple_GetItem(prog, 0); + } + if (globals == Py_None) { + globals = PyEval_GetGlobals(); + if (locals == Py_None) { + locals = PyEval_GetLocals(); + plain = 1; + } + } + else if (locals == Py_None) + locals = globals; + if (!PyString_Check(prog) && + !PyCode_Check(prog) && + !PyFile_Check(prog)) { + PyErr_SetString(PyExc_TypeError, + "exec 1st arg must be string, code or file object"); + return -1; + } + if (!PyDict_Check(globals) || !PyDict_Check(locals)) { + PyErr_SetString(PyExc_TypeError, + "exec 2nd/3rd args must be dict or None"); + return -1; + } + if (PyDict_GetItemString(globals, "__builtins__") == NULL) + PyDict_SetItemString(globals, "__builtins__", f->f_builtins); + if (PyCode_Check(prog)) { + if (PyEval_EvalCode((PyCodeObject *) prog, + globals, locals) == NULL) + return -1; + return 0; + } + if (PyFile_Check(prog)) { + FILE *fp = PyFile_AsFile(prog); + char *name = PyString_AsString(PyFile_Name(prog)); + if (PyRun_File(fp, name, Py_file_input, + globals, locals) == NULL) + return -1; + return 0; + } + s = PyString_AsString(prog); + if ((int)strlen(s) != PyString_Size(prog)) { + PyErr_SetString(PyExc_ValueError, + "embedded '\\0' in exec string"); + return -1; + } + v = PyRun_String(s, Py_file_input, globals, locals); + if (v == NULL) + return -1; + Py_DECREF(v); + if (plain) + PyFrame_LocalsToFast(f, 0); + return 0; +} + +/* Hack for ni.py */ +static PyObject * +find_from_args(f, nexti) + PyFrameObject *f; + int nexti; +{ + int opcode; + int oparg; + PyObject *list, *name; + unsigned char *next_instr; + + next_instr = GETUSTRINGVALUE(f->f_code->co_code) + nexti; + opcode = (*next_instr++); + if (opcode != IMPORT_FROM) { + Py_INCREF(Py_None); + return Py_None; + } + + list = PyList_New(0); + if (list == NULL) + return NULL; + + do { + oparg = (next_instr[1]<<8) + next_instr[0]; + next_instr += 2; + name = Getnamev(f, oparg); + if (PyList_Append(list, name) < 0) { + Py_DECREF(list); + break; + } + opcode = (*next_instr++); + } while (opcode == IMPORT_FROM); + + return list; +} + + +#ifdef DYNAMIC_EXECUTION_PROFILE + +PyObject * +getarray(a) + long a[256]; +{ + int i; + PyObject *l = PyList_New(256); + if (l == NULL) return NULL; + for (i = 0; i < 256; i++) { + PyObject *x = PyInt_FromLong(a[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + for (i = 0; i < 256; i++) + a[i] = 0; + return l; +} + +PyObject * +_Py_GetDXProfile(self, args) + PyObject *self, *args; +{ +#ifndef DXPAIRS + return getarray(dxp); +#else + int i; + PyObject *l = PyList_New(257); + if (l == NULL) return NULL; + for (i = 0; i < 257; i++) { + PyObject *x = getarray(dxpairs[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + return l; +#endif +} + +#endif diff --git a/src/main/resource/testFiles/cpython/prevFiles/prev_f62026_71eb864_Python#ceval.c b/src/main/resource/testFiles/cpython/prevFiles/prev_f62026_71eb864_Python#ceval.c new file mode 100644 index 0000000..1c51ccf --- /dev/null +++ b/src/main/resource/testFiles/cpython/prevFiles/prev_f62026_71eb864_Python#ceval.c @@ -0,0 +1,2880 @@ +/*********************************************************** +Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, +The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI or Corporation for National Research Initiatives or +CNRI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +While CWI is the initial source for this software, a modified version +is made available by the Corporation for National Research Initiatives +(CNRI) at the Internet address ftp://ftp.python.org. + +STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH +CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Execute compiled code */ + +/* XXX TO DO: + XXX how to pass arguments to call_trace? + XXX speed up searching for keywords by using a dictionary + XXX document it! + */ + +#include "Python.h" + +#include "compile.h" +#include "frameobject.h" +#include "eval.h" +#include "opcode.h" + +#include + +#ifdef HAVE_LIMITS_H +#include +#else +#define INT_MAX 2147483647 +#endif + +/* Turn this on if your compiler chokes on the big switch: */ +/* #define CASE_TOO_BIG 1 */ + +#ifdef Py_DEBUG +/* For debugging the interpreter: */ +#define LLTRACE 1 /* Low-level trace feature */ +#define CHECKEXC 1 /* Double-check exception checking */ +#endif + + +/* Forward declarations */ + +static PyObject *eval_code2 Py_PROTO((PyCodeObject *, + PyObject *, PyObject *, + PyObject **, int, + PyObject **, int, + PyObject **, int, + PyObject *)); +#ifdef LLTRACE +static int prtrace Py_PROTO((PyObject *, char *)); +#endif +static void call_exc_trace Py_PROTO((PyObject **, PyObject**, + PyFrameObject *)); +static int call_trace Py_PROTO((PyObject **, PyObject **, + PyFrameObject *, char *, PyObject *)); +static PyObject *call_builtin Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *call_function Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *loop_subscript Py_PROTO((PyObject *, PyObject *)); +static int slice_index Py_PROTO((PyObject *, int *)); +static PyObject *apply_slice Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int assign_slice Py_PROTO((PyObject *, PyObject *, + PyObject *, PyObject *)); +static PyObject *cmp_outcome Py_PROTO((int, PyObject *, PyObject *)); +static int import_from Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *build_class Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int exec_statement Py_PROTO((PyFrameObject *, + PyObject *, PyObject *, PyObject *)); +static PyObject *find_from_args Py_PROTO((PyFrameObject *, int)); +static void set_exc_info Py_PROTO((PyThreadState *, + PyObject *, PyObject *, PyObject *)); +static void reset_exc_info Py_PROTO((PyThreadState *)); + + +/* Dynamic execution profile */ +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS +static long dxpairs[257][256]; +#define dxp dxpairs[256] +#else +static long dxp[256]; +#endif +#endif + + +#ifdef WITH_THREAD + +#ifndef DONT_HAVE_ERRNO_H +#include +#endif +#include "pythread.h" + +extern int _PyThread_Started; /* Flag for Py_Exit */ + +static PyThread_type_lock interpreter_lock = 0; +static long main_thread = 0; + +void +PyEval_InitThreads() +{ + if (interpreter_lock) + return; + _PyThread_Started = 1; + interpreter_lock = PyThread_allocate_lock(); + PyThread_acquire_lock(interpreter_lock, 1); + main_thread = PyThread_get_thread_ident(); +} + +void +PyEval_AcquireLock() +{ + PyThread_acquire_lock(interpreter_lock, 1); +} + +void +PyEval_ReleaseLock() +{ + PyThread_release_lock(interpreter_lock); +} + +void +PyEval_AcquireThread(tstate) + PyThreadState *tstate; +{ + if (tstate == NULL) + Py_FatalError("PyEval_AcquireThread: NULL new thread state"); + PyThread_acquire_lock(interpreter_lock, 1); + if (PyThreadState_Swap(tstate) != NULL) + Py_FatalError( + "PyEval_AcquireThread: non-NULL old thread state"); +} + +void +PyEval_ReleaseThread(tstate) + PyThreadState *tstate; +{ + if (tstate == NULL) + Py_FatalError("PyEval_ReleaseThread: NULL thread state"); + if (PyThreadState_Swap(NULL) != tstate) + Py_FatalError("PyEval_ReleaseThread: wrong thread state"); + PyThread_release_lock(interpreter_lock); +} +#endif + +/* Functions save_thread and restore_thread are always defined so + dynamically loaded modules needn't be compiled separately for use + with and without threads: */ + +PyThreadState * +PyEval_SaveThread() +{ + PyThreadState *tstate = PyThreadState_Swap(NULL); + if (tstate == NULL) + Py_FatalError("PyEval_SaveThread: NULL tstate"); +#ifdef WITH_THREAD + if (interpreter_lock) + PyThread_release_lock(interpreter_lock); +#endif + return tstate; +} + +void +PyEval_RestoreThread(tstate) + PyThreadState *tstate; +{ + if (tstate == NULL) + Py_FatalError("PyEval_RestoreThread: NULL tstate"); +#ifdef WITH_THREAD + if (interpreter_lock) { + int err = errno; + PyThread_acquire_lock(interpreter_lock, 1); + errno = err; + } +#endif + PyThreadState_Swap(tstate); +} + + +/* Mechanism whereby asynchronously executing callbacks (e.g. UNIX + signal handlers or Mac I/O completion routines) can schedule calls + to a function to be called synchronously. + The synchronous function is called with one void* argument. + It should return 0 for success or -1 for failure -- failure should + be accompanied by an exception. + + If registry succeeds, the registry function returns 0; if it fails + (e.g. due to too many pending calls) it returns -1 (without setting + an exception condition). + + Note that because registry may occur from within signal handlers, + or other asynchronous events, calling malloc() is unsafe! + +#ifdef WITH_THREAD + Any thread can schedule pending calls, but only the main thread + will execute them. +#endif + + XXX WARNING! ASYNCHRONOUSLY EXECUTING CODE! + There are two possible race conditions: + (1) nested asynchronous registry calls; + (2) registry calls made while pending calls are being processed. + While (1) is very unlikely, (2) is a real possibility. + The current code is safe against (2), but not against (1). + The safety against (2) is derived from the fact that only one + thread (the main thread) ever takes things out of the queue. + + XXX Darn! With the advent of thread state, we should have an array + of pending calls per thread in the thread state! Later... +*/ + +#define NPENDINGCALLS 32 +static struct { + int (*func) Py_PROTO((ANY *)); + ANY *arg; +} pendingcalls[NPENDINGCALLS]; +static volatile int pendingfirst = 0; +static volatile int pendinglast = 0; +static volatile int things_to_do = 0; + +int +Py_AddPendingCall(func, arg) + int (*func) Py_PROTO((ANY *)); + ANY *arg; +{ + static int busy = 0; + int i, j; + /* XXX Begin critical section */ + /* XXX If you want this to be safe against nested + XXX asynchronous calls, you'll have to work harder! */ + if (busy) + return -1; + busy = 1; + i = pendinglast; + j = (i + 1) % NPENDINGCALLS; + if (j == pendingfirst) + return -1; /* Queue full */ + pendingcalls[i].func = func; + pendingcalls[i].arg = arg; + pendinglast = j; + things_to_do = 1; /* Signal main loop */ + busy = 0; + /* XXX End critical section */ + return 0; +} + +int +Py_MakePendingCalls() +{ + static int busy = 0; +#ifdef WITH_THREAD + if (main_thread && PyThread_get_thread_ident() != main_thread) + return 0; +#endif + if (busy) + return 0; + busy = 1; + things_to_do = 0; + for (;;) { + int i; + int (*func) Py_PROTO((ANY *)); + ANY *arg; + i = pendingfirst; + if (i == pendinglast) + break; /* Queue empty */ + func = pendingcalls[i].func; + arg = pendingcalls[i].arg; + pendingfirst = (i + 1) % NPENDINGCALLS; + if (func(arg) < 0) { + busy = 0; + things_to_do = 1; /* We're not done yet */ + return -1; + } + } + busy = 0; + return 0; +} + + +/* Status code for main loop (reason for stack unwind) */ + +enum why_code { + WHY_NOT, /* No error */ + WHY_EXCEPTION, /* Exception occurred */ + WHY_RERAISE, /* Exception re-raised by 'finally' */ + WHY_RETURN, /* 'return' statement */ + WHY_BREAK /* 'break' statement */ +}; + +static enum why_code do_raise Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int unpack_sequence Py_PROTO((PyObject *, int, PyObject **)); + + +/* Backward compatible interface */ + +PyObject * +PyEval_EvalCode(co, globals, locals) + PyCodeObject *co; + PyObject *globals; + PyObject *locals; +{ + return eval_code2(co, + globals, locals, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + (PyObject *)NULL); +} + + +/* Interpreter main loop */ + +#ifndef MAX_RECURSION_DEPTH +#define MAX_RECURSION_DEPTH 10000 +#endif + +static PyObject * +eval_code2(co, globals, locals, + args, argcount, kws, kwcount, defs, defcount, owner) + PyCodeObject *co; + PyObject *globals; + PyObject *locals; + PyObject **args; + int argcount; + PyObject **kws; /* length: 2*kwcount */ + int kwcount; + PyObject **defs; + int defcount; + PyObject *owner; +{ +#ifdef DXPAIRS + int lastopcode = 0; +#endif + register unsigned char *next_instr; + register int opcode; /* Current opcode */ + register int oparg; /* Current opcode argument, if any */ + register PyObject **stack_pointer; + register enum why_code why; /* Reason for block stack unwind */ + register int err; /* Error status -- nonzero if error */ + register PyObject *x; /* Result object -- NULL if error */ + register PyObject *v; /* Temporary objects popped off stack */ + register PyObject *w; + register PyObject *u; + register PyObject *t; + register PyFrameObject *f; /* Current frame */ + register PyObject **fastlocals; + PyObject *retval = NULL; /* Return value */ + PyThreadState *tstate = PyThreadState_GET(); + unsigned char *first_instr; +#ifdef LLTRACE + int lltrace; +#endif +#if defined(Py_DEBUG) || defined(LLTRACE) + /* Make it easier to find out where we are with a debugger */ + char *filename = PyString_AsString(co->co_filename); +#endif + +/* Code access macros */ + +#define GETCONST(i) Getconst(f, i) +#define GETNAME(i) Getname(f, i) +#define GETNAMEV(i) Getnamev(f, i) +#define INSTR_OFFSET() (next_instr - first_instr) +#define NEXTOP() (*next_instr++) +#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) +#define JUMPTO(x) (next_instr = first_instr + (x)) +#define JUMPBY(x) (next_instr += (x)) + +/* Stack manipulation macros */ + +#define STACK_LEVEL() (stack_pointer - f->f_valuestack) +#define EMPTY() (STACK_LEVEL() == 0) +#define TOP() (stack_pointer[-1]) +#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +#define BASIC_POP() (*--stack_pointer) + +#ifdef LLTRACE +#define PUSH(v) (BASIC_PUSH(v), lltrace && prtrace(TOP(), "push")) +#define POP() (lltrace && prtrace(TOP(), "pop"), BASIC_POP()) +#else +#define PUSH(v) BASIC_PUSH(v) +#define POP() BASIC_POP() +#endif + +/* Local variable macros */ + +#define GETLOCAL(i) (fastlocals[i]) +#define SETLOCAL(i, value) do { Py_XDECREF(GETLOCAL(i)); \ + GETLOCAL(i) = value; } while (0) + +/* Start of code */ + +#ifdef USE_STACKCHECK + if (tstate->recursion_depth%10 == 0 && PyOS_CheckStack()) { + PyErr_SetString(PyExc_MemoryError, "Stack overflow"); + return NULL; + } +#endif + + if (globals == NULL) { + PyErr_SetString(PyExc_SystemError, "eval_code2: NULL globals"); + return NULL; + } + +#ifdef LLTRACE + lltrace = PyDict_GetItemString(globals, "__lltrace__") != NULL; +#endif + + f = PyFrame_New( + tstate, /*back*/ + co, /*code*/ + globals, /*globals*/ + locals); /*locals*/ + if (f == NULL) + return NULL; + + tstate->frame = f; + fastlocals = f->f_localsplus; + + if (co->co_argcount > 0 || + co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { + int i; + int n = argcount; + PyObject *kwdict = NULL; + if (co->co_flags & CO_VARKEYWORDS) { + kwdict = PyDict_New(); + if (kwdict == NULL) + goto fail; + i = co->co_argcount; + if (co->co_flags & CO_VARARGS) + i++; + SETLOCAL(i, kwdict); + } + if (argcount > co->co_argcount) { + if (!(co->co_flags & CO_VARARGS)) { + PyErr_Format(PyExc_TypeError, + "too many arguments; expected %d, got %d", + co->co_argcount, argcount); + goto fail; + } + n = co->co_argcount; + } + for (i = 0; i < n; i++) { + x = args[i]; + Py_INCREF(x); + SETLOCAL(i, x); + } + if (co->co_flags & CO_VARARGS) { + u = PyTuple_New(argcount - n); + if (u == NULL) + goto fail; + SETLOCAL(co->co_argcount, u); + for (i = n; i < argcount; i++) { + x = args[i]; + Py_INCREF(x); + PyTuple_SET_ITEM(u, i-n, x); + } + } + for (i = 0; i < kwcount; i++) { + PyObject *keyword = kws[2*i]; + PyObject *value = kws[2*i + 1]; + int j; + /* XXX slow -- speed up using dictionary? */ + for (j = 0; j < co->co_argcount; j++) { + PyObject *nm = PyTuple_GET_ITEM( + co->co_varnames, j); + if (PyObject_Compare(keyword, nm) == 0) + break; + } + /* Check errors from Compare */ + if (PyErr_Occurred()) + goto fail; + if (j >= co->co_argcount) { + if (kwdict == NULL) { + PyErr_Format(PyExc_TypeError, + "unexpected keyword argument: %.400s", + PyString_AsString(keyword)); + goto fail; + } + PyDict_SetItem(kwdict, keyword, value); + } + else { + if (GETLOCAL(j) != NULL) { + PyErr_SetString(PyExc_TypeError, + "keyword parameter redefined"); + goto fail; + } + Py_INCREF(value); + SETLOCAL(j, value); + } + } + if (argcount < co->co_argcount) { + int m = co->co_argcount - defcount; + for (i = argcount; i < m; i++) { + if (GETLOCAL(i) == NULL) { + PyErr_Format(PyExc_TypeError, + "not enough arguments; expected %d, got %d", + m, i); + goto fail; + } + } + if (n > m) + i = n - m; + else + i = 0; + for (; i < defcount; i++) { + if (GETLOCAL(m+i) == NULL) { + PyObject *def = defs[i]; + Py_INCREF(def); + SETLOCAL(m+i, def); + } + } + } + } + else { + if (argcount > 0 || kwcount > 0) { + PyErr_SetString(PyExc_TypeError, + "no arguments expected"); + goto fail; + } + } + + if (tstate->sys_tracefunc != NULL) { + /* tstate->sys_tracefunc, if defined, is a function that + will be called on *every* entry to a code block. + Its return value, if not None, is a function that + will be called at the start of each executed line + of code. (Actually, the function must return + itself in order to continue tracing.) + The trace functions are called with three arguments: + a pointer to the current frame, a string indicating + why the function is called, and an argument which + depends on the situation. The global trace function + (sys.trace) is also called whenever an exception + is detected. */ + if (call_trace(&tstate->sys_tracefunc, + &f->f_trace, f, "call", + Py_None/*XXX how to compute arguments now?*/)) { + /* Trace function raised an error */ + goto fail; + } + } + + if (tstate->sys_profilefunc != NULL) { + /* Similar for sys_profilefunc, except it needn't return + itself and isn't called for "line" events */ + if (call_trace(&tstate->sys_profilefunc, + (PyObject**)0, f, "call", + Py_None/*XXX*/)) { + goto fail; + } + } + + if (++tstate->recursion_depth > MAX_RECURSION_DEPTH) { + --tstate->recursion_depth; + PyErr_SetString(PyExc_RuntimeError, + "Maximum recursion depth exceeded"); + tstate->frame = f->f_back; + Py_DECREF(f); + return NULL; + } + + _PyCode_GETCODEPTR(co, &first_instr); + next_instr = first_instr; + stack_pointer = f->f_valuestack; + + why = WHY_NOT; + err = 0; + x = Py_None; /* Not a reference, just anything non-NULL */ + + for (;;) { + /* Do periodic things. Doing this every time through + the loop would add too much overhead, so we do it + only every Nth instruction. We also do it if + ``things_to_do'' is set, i.e. when an asynchronous + event needs attention (e.g. a signal handler or + async I/O handler); see Py_AddPendingCall() and + Py_MakePendingCalls() above. */ + + if (things_to_do || --tstate->ticker < 0) { + tstate->ticker = tstate->interp->checkinterval; + if (things_to_do) { + if (Py_MakePendingCalls() < 0) { + why = WHY_EXCEPTION; + goto on_error; + } + } +#if !defined(HAVE_SIGNAL_H) || defined(macintosh) + /* If we have true signals, the signal handler + will call Py_AddPendingCall() so we don't + have to call sigcheck(). On the Mac and + DOS, alas, we have to call it. */ + if (PyErr_CheckSignals()) { + why = WHY_EXCEPTION; + goto on_error; + } +#endif + +#ifdef WITH_THREAD + if (interpreter_lock) { + /* Give another thread a chance */ + + if (PyThreadState_Swap(NULL) != tstate) + Py_FatalError("ceval: tstate mix-up"); + PyThread_release_lock(interpreter_lock); + + /* Other threads may run now */ + + PyThread_acquire_lock(interpreter_lock, 1); + if (PyThreadState_Swap(tstate) != NULL) + Py_FatalError("ceval: orphan tstate"); + } +#endif + } + + /* Extract opcode and argument */ + +#if defined(Py_DEBUG) || defined(LLTRACE) + f->f_lasti = INSTR_OFFSET(); +#endif + + opcode = NEXTOP(); + if (HAS_ARG(opcode)) + oparg = NEXTARG(); +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS + dxpairs[lastopcode][opcode]++; + lastopcode = opcode; +#endif + dxp[opcode]++; +#endif + +#ifdef LLTRACE + /* Instruction tracing */ + + if (lltrace) { + if (HAS_ARG(opcode)) { + printf("%d: %d, %d\n", + (int) (INSTR_OFFSET() - 3), + opcode, oparg); + } + else { + printf("%d: %d\n", + (int) (INSTR_OFFSET() - 1), opcode); + } + } +#endif + + /* Main switch on opcode */ + + switch (opcode) { + + /* BEWARE! + It is essential that any operation that fails sets either + x to NULL, err to nonzero, or why to anything but WHY_NOT, + and that no operation that succeeds does this! */ + + /* case STOP_CODE: this is an error! */ + + case POP_TOP: + v = POP(); + Py_DECREF(v); + continue; + + case ROT_TWO: + v = POP(); + w = POP(); + PUSH(v); + PUSH(w); + continue; + + case ROT_THREE: + v = POP(); + w = POP(); + x = POP(); + PUSH(v); + PUSH(x); + PUSH(w); + continue; + + case DUP_TOP: + v = TOP(); + Py_INCREF(v); + PUSH(v); + continue; + + case UNARY_POSITIVE: + v = POP(); + x = PyNumber_Positive(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_NEGATIVE: + v = POP(); + x = PyNumber_Negative(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_NOT: + v = POP(); + err = PyObject_IsTrue(v); + Py_DECREF(v); + if (err == 0) { + Py_INCREF(Py_True); + PUSH(Py_True); + continue; + } + else if (err > 0) { + Py_INCREF(Py_False); + PUSH(Py_False); + err = 0; + continue; + } + break; + + case UNARY_CONVERT: + v = POP(); + x = PyObject_Repr(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_INVERT: + v = POP(); + x = PyNumber_Invert(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_POWER: + w = POP(); + v = POP(); + x = PyNumber_Power(v, w, Py_None); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_MULTIPLY: + w = POP(); + v = POP(); + x = PyNumber_Multiply(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_DIVIDE: + w = POP(); + v = POP(); + x = PyNumber_Divide(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_MODULO: + w = POP(); + v = POP(); + x = PyNumber_Remainder(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_ADD: + w = POP(); + v = POP(); + if (PyInt_Check(v) && PyInt_Check(w)) { + /* INLINE: int + int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a + b; + if ((i^a) < 0 && (i^b) < 0) { + PyErr_SetString(PyExc_OverflowError, + "integer addition"); + x = NULL; + } + else + x = PyInt_FromLong(i); + } + else + x = PyNumber_Add(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_SUBTRACT: + w = POP(); + v = POP(); + if (PyInt_Check(v) && PyInt_Check(w)) { + /* INLINE: int - int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a - b; + if ((i^a) < 0 && (i^~b) < 0) { + PyErr_SetString(PyExc_OverflowError, + "integer subtraction"); + x = NULL; + } + else + x = PyInt_FromLong(i); + } + else + x = PyNumber_Subtract(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_SUBSCR: + w = POP(); + v = POP(); + if (PyList_Check(v) && PyInt_Check(w)) { + /* INLINE: list[int] */ + long i = PyInt_AsLong(w); + if (i < 0) + i += PyList_GET_SIZE(v); + if (i < 0 || + i >= PyList_GET_SIZE(v)) { + PyErr_SetString(PyExc_IndexError, + "list index out of range"); + x = NULL; + } + else { + x = PyList_GET_ITEM(v, i); + Py_INCREF(x); + } + } + else + x = PyObject_GetItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_LSHIFT: + w = POP(); + v = POP(); + x = PyNumber_Lshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_RSHIFT: + w = POP(); + v = POP(); + x = PyNumber_Rshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_AND: + w = POP(); + v = POP(); + x = PyNumber_And(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_XOR: + w = POP(); + v = POP(); + x = PyNumber_Xor(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_OR: + w = POP(); + v = POP(); + x = PyNumber_Or(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case SLICE+0: + case SLICE+1: + case SLICE+2: + case SLICE+3: + if ((opcode-SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + x = apply_slice(u, v, w); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case STORE_SLICE+0: + case STORE_SLICE+1: + case STORE_SLICE+2: + case STORE_SLICE+3: + if ((opcode-STORE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-STORE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + t = POP(); + err = assign_slice(u, v, w, t); /* u[v:w] = t */ + Py_DECREF(t); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case DELETE_SLICE+0: + case DELETE_SLICE+1: + case DELETE_SLICE+2: + case DELETE_SLICE+3: + if ((opcode-DELETE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-DELETE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + err = assign_slice(u, v, w, (PyObject *)NULL); + /* del u[v:w] */ + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case STORE_SUBSCR: + w = POP(); + v = POP(); + u = POP(); + /* v[w] = u */ + err = PyObject_SetItem(v, w, u); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case DELETE_SUBSCR: + w = POP(); + v = POP(); + /* del v[w] */ + err = PyObject_DelItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case PRINT_EXPR: + v = POP(); + /* Print value except if None */ + /* After printing, also assign to '_' */ + /* Before, set '_' to None to avoid recursion */ + if (v != Py_None && + (err = PyDict_SetItemString( + f->f_builtins, "_", Py_None)) == 0) { + err = Py_FlushLine(); + if (err == 0) { + x = PySys_GetObject("stdout"); + if (x == NULL) { + PyErr_SetString( + PyExc_RuntimeError, + "lost sys.stdout"); + err = -1; + } + } + if (err == 0) + err = PyFile_WriteObject(v, x, 0); + if (err == 0) { + PyFile_SoftSpace(x, 1); + err = Py_FlushLine(); + } + if (err == 0) { + err = PyDict_SetItemString( + f->f_builtins, "_", v); + } + } + Py_DECREF(v); + break; + + case PRINT_ITEM: + v = POP(); + w = PySys_GetObject("stdout"); + if (w == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "lost sys.stdout"); + err = -1; + } + else if (PyFile_SoftSpace(w, 1)) + err = PyFile_WriteString(" ", w); + if (err == 0) + err = PyFile_WriteObject(v, w, Py_PRINT_RAW); + if (err == 0 && PyString_Check(v)) { + /* XXX move into writeobject() ? */ + char *s = PyString_AsString(v); + int len = PyString_Size(v); + if (len > 0 && + isspace(Py_CHARMASK(s[len-1])) && + s[len-1] != ' ') + PyFile_SoftSpace(w, 0); + } + Py_DECREF(v); + if (err == 0) continue; + break; + + case PRINT_NEWLINE: + x = PySys_GetObject("stdout"); + if (x == NULL) + PyErr_SetString(PyExc_RuntimeError, + "lost sys.stdout"); + else { + err = PyFile_WriteString("\n", x); + if (err == 0) + PyFile_SoftSpace(x, 0); + } + break; + + case BREAK_LOOP: + why = WHY_BREAK; + break; + + case RAISE_VARARGS: + u = v = w = NULL; + switch (oparg) { + case 3: + u = POP(); /* traceback */ + /* Fallthrough */ + case 2: + v = POP(); /* value */ + /* Fallthrough */ + case 1: + w = POP(); /* exc */ + case 0: /* Fallthrough */ + why = do_raise(w, v, u); + break; + default: + PyErr_SetString(PyExc_SystemError, + "bad RAISE_VARARGS oparg"); + why = WHY_EXCEPTION; + break; + } + break; + + case LOAD_LOCALS: + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + Py_INCREF(x); + PUSH(x); + break; + + case RETURN_VALUE: + retval = POP(); + why = WHY_RETURN; + break; + + case EXEC_STMT: + w = POP(); + v = POP(); + u = POP(); + err = exec_statement(f, u, v, w); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case POP_BLOCK: + { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_DECREF(v); + } + } + break; + + case END_FINALLY: + v = POP(); + if (PyInt_Check(v)) { + why = (enum why_code) PyInt_AsLong(v); + if (why == WHY_RETURN) + retval = POP(); + } + else if (PyString_Check(v) || PyClass_Check(v)) { + w = POP(); + u = POP(); + PyErr_Restore(v, w, u); + why = WHY_RERAISE; + break; + } + else if (v != Py_None) { + PyErr_SetString(PyExc_SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; + } + Py_DECREF(v); + break; + + case BUILD_CLASS: + u = POP(); + v = POP(); + w = POP(); + x = build_class(u, v, w); + PUSH(x); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case STORE_NAME: + w = GETNAMEV(oparg); + v = POP(); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + err = PyDict_SetItem(x, w, v); + Py_DECREF(v); + break; + + case DELETE_NAME: + w = GETNAMEV(oparg); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + if ((err = PyDict_DelItem(x, w)) != 0) + PyErr_SetObject(PyExc_NameError, w); + break; + +#ifdef CASE_TOO_BIG + default: switch (opcode) { +#endif + + case UNPACK_TUPLE: + case UNPACK_LIST: + v = POP(); + if (PyTuple_Check(v)) { + if (PyTuple_Size(v) != oparg) { + PyErr_SetString(PyExc_ValueError, + "unpack tuple of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = PyTuple_GET_ITEM(v, oparg); + Py_INCREF(w); + PUSH(w); + } + } + } + else if (PyList_Check(v)) { + if (PyList_Size(v) != oparg) { + PyErr_SetString(PyExc_ValueError, + "unpack list of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = PyList_GET_ITEM(v, oparg); + Py_INCREF(w); + PUSH(w); + } + } + } + else if (PySequence_Check(v)) { + if (unpack_sequence(v, oparg, + stack_pointer + oparg)) + stack_pointer += oparg; + else + why = WHY_EXCEPTION; + } + else { + PyErr_SetString(PyExc_TypeError, + "unpack non-sequence"); + why = WHY_EXCEPTION; + } + Py_DECREF(v); + break; + + case STORE_ATTR: + w = GETNAMEV(oparg); + v = POP(); + u = POP(); + err = PyObject_SetAttr(v, w, u); /* v.w = u */ + Py_DECREF(v); + Py_DECREF(u); + break; + + case DELETE_ATTR: + w = GETNAMEV(oparg); + v = POP(); + err = PyObject_SetAttr(v, w, (PyObject *)NULL); + /* del v.w */ + Py_DECREF(v); + break; + + case STORE_GLOBAL: + w = GETNAMEV(oparg); + v = POP(); + err = PyDict_SetItem(f->f_globals, w, v); + Py_DECREF(v); + break; + + case DELETE_GLOBAL: + w = GETNAMEV(oparg); + if ((err = PyDict_DelItem(f->f_globals, w)) != 0) + PyErr_SetObject(PyExc_NameError, w); + break; + + case LOAD_CONST: + x = GETCONST(oparg); + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_NAME: + w = GETNAMEV(oparg); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + x = PyDict_GetItem(x, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + PyErr_SetObject( + PyExc_NameError, w); + break; + } + } + } + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_GLOBAL: + w = GETNAMEV(oparg); + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + PyErr_SetObject(PyExc_NameError, w); + break; + } + } + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_FAST: + x = GETLOCAL(oparg); + if (x == NULL) { + PyErr_SetObject(PyExc_UnboundLocalError, + PyTuple_GetItem(co->co_varnames, + oparg)); + break; + } + Py_INCREF(x); + PUSH(x); + if (x != NULL) continue; + break; + + case STORE_FAST: + v = POP(); + SETLOCAL(oparg, v); + continue; + + case DELETE_FAST: + x = GETLOCAL(oparg); + if (x == NULL) { + PyErr_SetObject(PyExc_UnboundLocalError, + PyTuple_GetItem(co->co_varnames, + oparg)); + break; + } + SETLOCAL(oparg, NULL); + continue; + + case BUILD_TUPLE: + x = PyTuple_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + PyTuple_SET_ITEM(x, oparg, w); + } + PUSH(x); + continue; + } + break; + + case BUILD_LIST: + x = PyList_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + PyList_SET_ITEM(x, oparg, w); + } + PUSH(x); + continue; + } + break; + + case BUILD_MAP: + x = PyDict_New(); + PUSH(x); + if (x != NULL) continue; + break; + + case LOAD_ATTR: + w = GETNAMEV(oparg); + v = POP(); + x = PyObject_GetAttr(v, w); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case COMPARE_OP: + w = POP(); + v = POP(); + if (PyInt_Check(v) && PyInt_Check(w)) { + /* INLINE: cmp(int, int) */ + register long a, b; + register int res; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + switch (oparg) { + case LT: res = a < b; break; + case LE: res = a <= b; break; + case EQ: res = a == b; break; + case NE: res = a != b; break; + case GT: res = a > b; break; + case GE: res = a >= b; break; + case IS: res = v == w; break; + case IS_NOT: res = v != w; break; + default: goto slow_compare; + } + x = res ? Py_True : Py_False; + Py_INCREF(x); + } + else { + slow_compare: + x = cmp_outcome(oparg, v, w); + } + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case IMPORT_NAME: + w = GETNAMEV(oparg); + x = PyDict_GetItemString(f->f_builtins, "__import__"); + if (x == NULL) { + PyErr_SetString(PyExc_ImportError, + "__import__ not found"); + break; + } + u = find_from_args(f, INSTR_OFFSET()); + if (u == NULL) { + x = u; + break; + } + w = Py_BuildValue("(OOOO)", + w, + f->f_globals, + f->f_locals == NULL ? + Py_None : f->f_locals, + u); + Py_DECREF(u); + if (w == NULL) { + x = NULL; + break; + } + x = PyEval_CallObject(x, w); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case IMPORT_FROM: + w = GETNAMEV(oparg); + v = TOP(); + PyFrame_FastToLocals(f); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + err = import_from(x, v, w); + PyFrame_LocalsToFast(f, 0); + if (err == 0) continue; + break; + + case JUMP_FORWARD: + JUMPBY(oparg); + continue; + + case JUMP_IF_FALSE: + err = PyObject_IsTrue(TOP()); + if (err > 0) + err = 0; + else if (err == 0) + JUMPBY(oparg); + else + break; + continue; + + case JUMP_IF_TRUE: + err = PyObject_IsTrue(TOP()); + if (err > 0) { + err = 0; + JUMPBY(oparg); + } + else if (err == 0) + ; + else + break; + continue; + + case JUMP_ABSOLUTE: + JUMPTO(oparg); + continue; + + case FOR_LOOP: + /* for v in s: ... + On entry: stack contains s, i. + On exit: stack contains s, i+1, s[i]; + but if loop exhausted: + s, i are popped, and we jump */ + w = POP(); /* Loop index */ + v = POP(); /* Sequence object */ + u = loop_subscript(v, w); + if (u != NULL) { + PUSH(v); + x = PyInt_FromLong(PyInt_AsLong(w)+1); + PUSH(x); + Py_DECREF(w); + PUSH(u); + if (x != NULL) continue; + } + else { + Py_DECREF(v); + Py_DECREF(w); + /* A NULL can mean "s exhausted" + but also an error: */ + if (PyErr_Occurred()) + why = WHY_EXCEPTION; + else { + JUMPBY(oparg); + continue; + } + } + break; + + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); + continue; + + case SET_LINENO: +#ifdef LLTRACE + if (lltrace) + printf("--- %s:%d \n", filename, oparg); +#endif + f->f_lineno = oparg; + if (f->f_trace == NULL) + continue; + /* Trace each line of code reached */ + f->f_lasti = INSTR_OFFSET(); + err = call_trace(&f->f_trace, &f->f_trace, + f, "line", Py_None); + break; + + case CALL_FUNCTION: + { + int na = oparg & 0xff; + int nk = (oparg>>8) & 0xff; + int n = na + 2*nk; + PyObject **pfunc = stack_pointer - n - 1; + PyObject *func = *pfunc; + PyObject *self = NULL; + PyObject *class = NULL; + f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */ + if (PyMethod_Check(func)) { + self = PyMethod_Self(func); + class = PyMethod_Class(func); + func = PyMethod_Function(func); + Py_INCREF(func); + if (self != NULL) { + Py_INCREF(self); + Py_DECREF(*pfunc); + *pfunc = self; + na++; + n++; + } + else { + /* Unbound methods must be + called with an instance of + the class (or a derived + class) as first argument */ + if (na > 0 && + (self = stack_pointer[-n]) + != NULL && + PyInstance_Check(self) && + PyClass_IsSubclass( + (PyObject *) + (((PyInstanceObject *)self) + ->in_class), + class)) + /* Handy-dandy */ ; + else { + PyErr_SetString( + PyExc_TypeError, + "unbound method must be called with class instance 1st argument"); + x = NULL; + break; + } + } + } + else + Py_INCREF(func); + if (PyFunction_Check(func)) { + PyObject *co = PyFunction_GetCode(func); + PyObject *globals = + PyFunction_GetGlobals(func); + PyObject *argdefs = + PyFunction_GetDefaults(func); + PyObject **d; + int nd; + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = ((PyTupleObject *)argdefs) -> + ob_size; + } + else { + d = NULL; + nd = 0; + } + x = eval_code2( + (PyCodeObject *)co, + globals, (PyObject *)NULL, + stack_pointer-n, na, + stack_pointer-2*nk, nk, + d, nd, + class); + } + else { + PyObject *args = PyTuple_New(na); + PyObject *kwdict = NULL; + if (args == NULL) { + x = NULL; + break; + } + if (nk > 0) { + kwdict = PyDict_New(); + if (kwdict == NULL) { + x = NULL; + break; + } + err = 0; + while (--nk >= 0) { + PyObject *value = POP(); + PyObject *key = POP(); + err = PyDict_SetItem( + kwdict, key, value); + Py_DECREF(key); + Py_DECREF(value); + if (err) + break; + } + if (err) { + Py_DECREF(args); + Py_DECREF(kwdict); + break; + } + } + while (--na >= 0) { + w = POP(); + PyTuple_SET_ITEM(args, na, w); + } + x = PyEval_CallObjectWithKeywords( + func, args, kwdict); + Py_DECREF(args); + Py_XDECREF(kwdict); + } + Py_DECREF(func); + while (stack_pointer > pfunc) { + w = POP(); + Py_DECREF(w); + } + PUSH(x); + if (x != NULL) continue; + break; + } + + case MAKE_FUNCTION: + v = POP(); /* code object */ + x = PyFunction_New(v, f->f_globals); + Py_DECREF(v); + /* XXX Maybe this should be a separate opcode? */ + if (x != NULL && oparg > 0) { + v = PyTuple_New(oparg); + if (v == NULL) { + Py_DECREF(x); + x = NULL; + break; + } + while (--oparg >= 0) { + w = POP(); + PyTuple_SET_ITEM(v, oparg, w); + } + err = PyFunction_SetDefaults(x, v); + Py_DECREF(v); + } + PUSH(x); + break; + + case BUILD_SLICE: + if (oparg == 3) + w = POP(); + else + w = NULL; + v = POP(); + u = POP(); + x = PySlice_New(u, v, w); + Py_DECREF(u); + Py_DECREF(v); + Py_XDECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + + default: + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + f->f_lineno, opcode); + PyErr_SetString(PyExc_SystemError, "unknown opcode"); + why = WHY_EXCEPTION; + break; + +#ifdef CASE_TOO_BIG + } +#endif + + } /* switch */ + + on_error: + + /* Quickly continue if no error occurred */ + + if (why == WHY_NOT) { + if (err == 0 && x != NULL) { +#ifdef CHECKEXC + /* This check is expensive! */ + if (PyErr_Occurred()) + fprintf(stderr, + "XXX undetected error\n"); + else +#endif + continue; /* Normal, fast path */ + } + why = WHY_EXCEPTION; + x = Py_None; + err = 0; + } + + /* Double-check exception status */ + + if (why == WHY_EXCEPTION || why == WHY_RERAISE) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_SystemError, + "error return without exception set"); + why = WHY_EXCEPTION; + } + } +#ifdef CHECKEXC + else { + /* This check is expensive! */ + if (PyErr_Occurred()) { + fprintf(stderr, + "XXX undetected error (why=%d)\n", + why); + why = WHY_EXCEPTION; + } + } +#endif + + /* Log traceback info if this is a real exception */ + + if (why == WHY_EXCEPTION) { + f->f_lasti = INSTR_OFFSET() - 1; + if (HAS_ARG(opcode)) + f->f_lasti -= 2; + PyTraceBack_Here(f); + + if (f->f_trace) + call_exc_trace(&f->f_trace, &f->f_trace, f); + if (tstate->sys_profilefunc) + call_exc_trace(&tstate->sys_profilefunc, + (PyObject**)0, f); + } + + /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ + + if (why == WHY_RERAISE) + why = WHY_EXCEPTION; + + /* Unwind stacks if a (pseudo) exception occurred */ + + while (why != WHY_NOT && f->f_iblock > 0) { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_XDECREF(v); + } + if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + if (b->b_type == SETUP_FINALLY || + (b->b_type == SETUP_EXCEPT && + why == WHY_EXCEPTION)) { + if (why == WHY_EXCEPTION) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (val == NULL) { + val = Py_None; + Py_INCREF(val); + } + /* Make the raw exception data + available to the handler, + so a program can emulate the + Python main loop. Don't do + this for 'finally'. */ + if (b->b_type == SETUP_EXCEPT) { + PyErr_NormalizeException( + &exc, &val, &tb); + set_exc_info(tstate, + exc, val, tb); + } + PUSH(tb); + PUSH(val); + PUSH(exc); + } + else { + if (why == WHY_RETURN) + PUSH(retval); + v = PyInt_FromLong((long)why); + PUSH(v); + } + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + } /* unwind stack */ + + /* End the loop if we still have an error (or return) */ + + if (why != WHY_NOT) + break; + + } /* main loop */ + + /* Pop remaining stack entries */ + + while (!EMPTY()) { + v = POP(); + Py_XDECREF(v); + } + + if (why != WHY_RETURN) + retval = NULL; + + if (f->f_trace) { + if (why == WHY_RETURN) { + if (call_trace(&f->f_trace, &f->f_trace, f, + "return", retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + } + + if (tstate->sys_profilefunc && why == WHY_RETURN) { + if (call_trace(&tstate->sys_profilefunc, (PyObject**)0, + f, "return", retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + + reset_exc_info(tstate); + + --tstate->recursion_depth; + + fail: /* Jump here from prelude on failure */ + + /* Restore previous frame and release the current one */ + + tstate->frame = f->f_back; + Py_DECREF(f); + + return retval; +} + +static void +set_exc_info(tstate, type, value, tb) + PyThreadState *tstate; + PyObject *type; + PyObject *value; + PyObject *tb; +{ + PyFrameObject *frame; + PyObject *tmp_type, *tmp_value, *tmp_tb; + + frame = tstate->frame; + if (frame->f_exc_type == NULL) { + /* This frame didn't catch an exception before */ + /* Save previous exception of this thread in this frame */ + if (tstate->exc_type == NULL) { + Py_INCREF(Py_None); + tstate->exc_type = Py_None; + } + tmp_type = frame->f_exc_type; + tmp_value = frame->f_exc_value; + tmp_tb = frame->f_exc_traceback; + Py_XINCREF(tstate->exc_type); + Py_XINCREF(tstate->exc_value); + Py_XINCREF(tstate->exc_traceback); + frame->f_exc_type = tstate->exc_type; + frame->f_exc_value = tstate->exc_value; + frame->f_exc_traceback = tstate->exc_traceback; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + } + /* Set new exception for this thread */ + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + Py_XINCREF(type); + Py_XINCREF(value); + Py_XINCREF(tb); + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + /* For b/w compatibility */ + PySys_SetObject("exc_type", type); + PySys_SetObject("exc_value", value); + PySys_SetObject("exc_traceback", tb); +} + +static void +reset_exc_info(tstate) + PyThreadState *tstate; +{ + PyFrameObject *frame; + PyObject *tmp_type, *tmp_value, *tmp_tb; + frame = tstate->frame; + if (frame->f_exc_type != NULL) { + /* This frame caught an exception */ + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + Py_XINCREF(frame->f_exc_type); + Py_XINCREF(frame->f_exc_value); + Py_XINCREF(frame->f_exc_traceback); + tstate->exc_type = frame->f_exc_type; + tstate->exc_value = frame->f_exc_value; + tstate->exc_traceback = frame->f_exc_traceback; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + /* For b/w compatibility */ + PySys_SetObject("exc_type", frame->f_exc_type); + PySys_SetObject("exc_value", frame->f_exc_value); + PySys_SetObject("exc_traceback", frame->f_exc_traceback); + } + tmp_type = frame->f_exc_type; + tmp_value = frame->f_exc_value; + tmp_tb = frame->f_exc_traceback; + frame->f_exc_type = NULL; + frame->f_exc_value = NULL; + frame->f_exc_traceback = NULL; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} + +/* Logic for the raise statement (too complicated for inlining). + This *consumes* a reference count to each of its arguments. */ +static enum why_code +do_raise(type, value, tb) + PyObject *type, *value, *tb; +{ + if (type == NULL) { + /* Reraise */ + PyThreadState *tstate = PyThreadState_Get(); + type = tstate->exc_type == NULL ? Py_None : tstate->exc_type; + value = tstate->exc_value; + tb = tstate->exc_traceback; + Py_XINCREF(type); + Py_XINCREF(value); + Py_XINCREF(tb); + } + + /* We support the following forms of raise: + raise , + raise , + raise , None + raise , + raise , None + raise , + raise , None + + An omitted second argument is the same as None. + + In addition, raise , is the same as + raising the tuple's first item (and it better have one!); + this rule is applied recursively. + + Finally, an optional third argument can be supplied, which + gives the traceback to be substituted (useful when + re-raising an exception after examining it). */ + + /* First, check the traceback argument, replacing None with + NULL. */ + if (tb == Py_None) { + Py_DECREF(tb); + tb = NULL; + } + else if (tb != NULL && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise 3rd arg must be traceback or None"); + goto raise_error; + } + + /* Next, replace a missing value with None */ + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + + /* Next, repeatedly, replace a tuple exception with its first item */ + while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { + PyObject *tmp = type; + type = PyTuple_GET_ITEM(type, 0); + Py_INCREF(type); + Py_DECREF(tmp); + } + + if (PyString_Check(type)) + ; + + else if (PyClass_Check(type)) + PyErr_NormalizeException(&type, &value, &tb); + + else if (PyInstance_Check(type)) { + /* Raising an instance. The value should be a dummy. */ + if (value != Py_None) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + else { + /* Normalize to raise , */ + Py_DECREF(value); + value = type; + type = (PyObject*) ((PyInstanceObject*)type)->in_class; + Py_INCREF(type); + } + } + else { + /* Not something you can raise. You get an exception + anyway, just not what you specified :-) */ + PyErr_SetString(PyExc_TypeError, + "exceptions must be strings, classes, or instances"); + goto raise_error; + } + PyErr_Restore(type, value, tb); + if (tb == NULL) + return WHY_EXCEPTION; + else + return WHY_RERAISE; + raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return WHY_EXCEPTION; +} + +static int +unpack_sequence(v, argcnt, sp) + PyObject *v; + int argcnt; + PyObject **sp; +{ + int i; + PyObject *w; + + for (i = 0; i < argcnt; i++) { + if (! (w = PySequence_GetItem(v, i))) { + if (PyErr_ExceptionMatches(PyExc_IndexError)) + PyErr_SetString(PyExc_ValueError, + "unpack sequence of wrong size"); + goto finally; + } + *--sp = w; + } + /* we better get an IndexError now */ + if (PySequence_GetItem(v, i) == NULL) { + if (PyErr_ExceptionMatches(PyExc_IndexError)) { + PyErr_Clear(); + return 1; + } + /* some other exception occurred. fall through to finally */ + } + else + PyErr_SetString(PyExc_ValueError, + "unpack sequence of wrong size"); + /* fall through */ +finally: + for (; i > 0; i--, sp++) + Py_DECREF(*sp); + + return 0; +} + + +#ifdef LLTRACE +static int +prtrace(v, str) + PyObject *v; + char *str; +{ + printf("%s ", str); + if (PyObject_Print(v, stdout, 0) != 0) + PyErr_Clear(); /* Don't know what else to do */ + printf("\n"); +} +#endif + +static void +call_exc_trace(p_trace, p_newtrace, f) + PyObject **p_trace, **p_newtrace; + PyFrameObject *f; +{ + PyObject *type, *value, *traceback, *arg; + int err; + PyErr_Fetch(&type, &value, &traceback); + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + arg = Py_BuildValue("(OOO)", type, value, traceback); + if (arg == NULL) { + PyErr_Restore(type, value, traceback); + return; + } + err = call_trace(p_trace, p_newtrace, f, "exception", arg); + Py_DECREF(arg); + if (err == 0) + PyErr_Restore(type, value, traceback); + else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } +} + +static int +call_trace(p_trace, p_newtrace, f, msg, arg) + PyObject **p_trace; /* in/out; may not be NULL; + may not point to NULL variable initially */ + PyObject **p_newtrace; /* in/out; may be NULL; + may point to NULL variable; + may be same variable as p_newtrace */ + PyFrameObject *f; + char *msg; + PyObject *arg; +{ + PyThreadState *tstate = f->f_tstate; + PyObject *args, *what; + PyObject *res = NULL; + + if (tstate->tracing) { + /* Don't do recursive traces */ + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + *p_newtrace = NULL; + } + return 0; + } + + args = PyTuple_New(3); + if (args == NULL) + goto cleanup; + what = PyString_FromString(msg); + if (what == NULL) + goto cleanup; + Py_INCREF(f); + PyTuple_SET_ITEM(args, 0, (PyObject *)f); + PyTuple_SET_ITEM(args, 1, what); + if (arg == NULL) + arg = Py_None; + Py_INCREF(arg); + PyTuple_SET_ITEM(args, 2, arg); + tstate->tracing++; + PyFrame_FastToLocals(f); + res = PyEval_CallObject(*p_trace, args); /* May clear *p_trace! */ + PyFrame_LocalsToFast(f, 1); + tstate->tracing--; + cleanup: + Py_XDECREF(args); + if (res == NULL) { + /* The trace proc raised an exception */ + PyTraceBack_Here(f); + Py_XDECREF(*p_trace); + *p_trace = NULL; + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + *p_newtrace = NULL; + } + return -1; + } + else { + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + if (res == Py_None) + *p_newtrace = NULL; + else { + Py_INCREF(res); + *p_newtrace = res; + } + } + Py_DECREF(res); + return 0; + } +} + +PyObject * +PyEval_GetBuiltins() +{ + PyThreadState *tstate = PyThreadState_Get(); + PyFrameObject *current_frame = tstate->frame; + if (current_frame == NULL) + return tstate->interp->builtins; + else + return current_frame->f_builtins; +} + +PyObject * +PyEval_GetLocals() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + if (current_frame == NULL) + return NULL; + PyFrame_FastToLocals(current_frame); + return current_frame->f_locals; +} + +PyObject * +PyEval_GetGlobals() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + if (current_frame == NULL) + return NULL; + else + return current_frame->f_globals; +} + +PyObject * +PyEval_GetFrame() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + return (PyObject *)current_frame; +} + +int +PyEval_GetRestricted() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + return current_frame == NULL ? 0 : current_frame->f_restricted; +} + +int +Py_FlushLine() +{ + PyObject *f = PySys_GetObject("stdout"); + if (f == NULL) + return 0; + if (!PyFile_SoftSpace(f, 0)) + return 0; + return PyFile_WriteString("\n", f); +} + + +/* External interface to call any callable object. + The arg must be a tuple or NULL. */ + +#undef PyEval_CallObject +/* for backward compatibility: export this interface */ + +PyObject * +PyEval_CallObject(func, arg) + PyObject *func; + PyObject *arg; +{ + return PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL); +} +#define PyEval_CallObject(func,arg) \ + PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL) + +PyObject * +PyEval_CallObjectWithKeywords(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + ternaryfunc call; + PyObject *result; + + if (arg == NULL) + arg = PyTuple_New(0); + else if (!PyTuple_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "argument list must be a tuple"); + return NULL; + } + else + Py_INCREF(arg); + + if (kw != NULL && !PyDict_Check(kw)) { + PyErr_SetString(PyExc_TypeError, + "keyword list must be a dictionary"); + return NULL; + } + + if ((call = func->ob_type->tp_call) != NULL) + result = (*call)(func, arg, kw); + else if (PyMethod_Check(func) || PyFunction_Check(func)) + result = call_function(func, arg, kw); + else + result = call_builtin(func, arg, kw); + + Py_DECREF(arg); + + if (result == NULL && !PyErr_Occurred()) + PyErr_SetString(PyExc_SystemError, + "NULL result without error in call_object"); + + return result; +} + +static PyObject * +call_builtin(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + if (PyCFunction_Check(func)) { + PyCFunction meth = PyCFunction_GetFunction(func); + PyObject *self = PyCFunction_GetSelf(func); + int flags = PyCFunction_GetFlags(func); + if (!(flags & METH_VARARGS)) { + int size = PyTuple_Size(arg); + if (size == 1) + arg = PyTuple_GET_ITEM(arg, 0); + else if (size == 0) + arg = NULL; + } + if (flags & METH_KEYWORDS) + return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); + if (kw != NULL && PyDict_Size(kw) != 0) { + PyErr_SetString(PyExc_TypeError, + "this function takes no keyword arguments"); + return NULL; + } + return (*meth)(self, arg); + } + if (PyClass_Check(func)) { + return PyInstance_New(func, arg, kw); + } + if (PyInstance_Check(func)) { + PyObject *res, *call = PyObject_GetAttrString(func,"__call__"); + if (call == NULL) { + PyErr_Clear(); + PyErr_SetString(PyExc_AttributeError, + "no __call__ method defined"); + return NULL; + } + res = PyEval_CallObjectWithKeywords(call, arg, kw); + Py_DECREF(call); + return res; + } + PyErr_Format(PyExc_TypeError, "call of non-function (type %s)", + func->ob_type->tp_name); + return NULL; +} + +static PyObject * +call_function(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + PyObject *class = NULL; /* == owner */ + PyObject *argdefs; + PyObject **d, **k; + int nk, nd; + PyObject *result; + + if (kw != NULL && !PyDict_Check(kw)) { + PyErr_BadInternalCall(); + return NULL; + } + + if (PyMethod_Check(func)) { + PyObject *self = PyMethod_Self(func); + class = PyMethod_Class(func); + func = PyMethod_Function(func); + if (self == NULL) { + /* Unbound methods must be called with an instance of + the class (or a derived class) as first argument */ + if (PyTuple_Size(arg) >= 1) { + self = PyTuple_GET_ITEM(arg, 0); + if (self != NULL && + PyInstance_Check(self) && + PyClass_IsSubclass((PyObject *) + (((PyInstanceObject *)self)->in_class), + class)) + /* Handy-dandy */ ; + else + self = NULL; + } + if (self == NULL) { + PyErr_SetString(PyExc_TypeError, + "unbound method must be called with class instance 1st argument"); + return NULL; + } + Py_INCREF(arg); + } + else { + int argcount = PyTuple_Size(arg); + PyObject *newarg = PyTuple_New(argcount + 1); + int i; + if (newarg == NULL) + return NULL; + Py_INCREF(self); + PyTuple_SET_ITEM(newarg, 0, self); + for (i = 0; i < argcount; i++) { + PyObject *v = PyTuple_GET_ITEM(arg, i); + Py_XINCREF(v); + PyTuple_SET_ITEM(newarg, i+1, v); + } + arg = newarg; + } + if (!PyFunction_Check(func)) { + result = PyEval_CallObjectWithKeywords(func, arg, kw); + Py_DECREF(arg); + return result; + } + } + else { + if (!PyFunction_Check(func)) { + PyErr_Format(PyExc_TypeError, + "call of non-function (type %s)", + func->ob_type->tp_name); + return NULL; + } + Py_INCREF(arg); + } + + argdefs = PyFunction_GetDefaults(func); + if (argdefs != NULL && PyTuple_Check(argdefs)) { + d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0); + nd = PyTuple_Size(argdefs); + } + else { + d = NULL; + nd = 0; + } + + if (kw != NULL) { + int pos, i; + nk = PyDict_Size(kw); + k = PyMem_NEW(PyObject *, 2*nk); + if (k == NULL) { + PyErr_NoMemory(); + Py_DECREF(arg); + return NULL; + } + pos = i = 0; + while (PyDict_Next(kw, &pos, &k[i], &k[i+1])) + i += 2; + nk = i/2; + /* XXX This is broken if the caller deletes dict items! */ + } + else { + k = NULL; + nk = 0; + } + + result = eval_code2( + (PyCodeObject *)PyFunction_GetCode(func), + PyFunction_GetGlobals(func), (PyObject *)NULL, + &PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg), + k, nk, + d, nd, + class); + + Py_DECREF(arg); + PyMem_XDEL(k); + + return result; +} + +#define SLICE_ERROR_MSG \ + "standard sequence type does not support step size other than one" + +static PyObject * +loop_subscript(v, w) + PyObject *v, *w; +{ + PySequenceMethods *sq = v->ob_type->tp_as_sequence; + int i; + if (sq == NULL || sq->sq_item == NULL) { + PyErr_SetString(PyExc_TypeError, "loop over non-sequence"); + return NULL; + } + i = PyInt_AsLong(w); + v = (*sq->sq_item)(v, i); + if (v) + return v; + if (PyErr_ExceptionMatches(PyExc_IndexError)) + PyErr_Clear(); + return NULL; +} + +static int +slice_index(v, pi) + PyObject *v; + int *pi; +{ + if (v != NULL) { + long x; + if (!PyInt_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "slice index must be int"); + return -1; + } + x = PyInt_AsLong(v); + /* Truncate -- very long indices are truncated anyway */ + if (x > INT_MAX) + x = INT_MAX; + else if (x < -INT_MAX) + x = 0; + *pi = x; + } + return 0; +} + +static PyObject * +apply_slice(u, v, w) /* return u[v:w] */ + PyObject *u, *v, *w; +{ + int ilow = 0, ihigh = INT_MAX; + if (slice_index(v, &ilow) != 0) + return NULL; + if (slice_index(w, &ihigh) != 0) + return NULL; + return PySequence_GetSlice(u, ilow, ihigh); +} + +static int +assign_slice(u, v, w, x) /* u[v:w] = x */ + PyObject *u, *v, *w, *x; +{ + int ilow = 0, ihigh = INT_MAX; + if (slice_index(v, &ilow) != 0) + return -1; + if (slice_index(w, &ihigh) != 0) + return -1; + if (x == NULL) + return PySequence_DelSlice(u, ilow, ihigh); + else + return PySequence_SetSlice(u, ilow, ihigh, x); +} + +static PyObject * +cmp_outcome(op, v, w) + int op; + register PyObject *v; + register PyObject *w; +{ + register int cmp; + register int res = 0; + switch (op) { + case IS: + case IS_NOT: + res = (v == w); + if (op == (int) IS_NOT) + res = !res; + break; + case IN: + case NOT_IN: + res = PySequence_Contains(w, v); + if (res < 0) + return NULL; + if (op == (int) NOT_IN) + res = !res; + break; + case EXC_MATCH: + res = PyErr_GivenExceptionMatches(v, w); + break; + default: + cmp = PyObject_Compare(v, w); + if (cmp && PyErr_Occurred()) + return NULL; + switch (op) { + case LT: res = cmp < 0; break; + case LE: res = cmp <= 0; break; + case EQ: res = cmp == 0; break; + case NE: res = cmp != 0; break; + case GT: res = cmp > 0; break; + case GE: res = cmp >= 0; break; + /* XXX no default? (res is initialized to 0 though) */ + } + } + v = res ? Py_True : Py_False; + Py_INCREF(v); + return v; +} + +static int +import_from(locals, v, name) + PyObject *locals; + PyObject *v; + PyObject *name; +{ + PyObject *w, *x; + if (!PyModule_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "import-from requires module object"); + return -1; + } + w = PyModule_GetDict(v); + if (PyString_AsString(name)[0] == '*') { + int pos, err; + PyObject *name, *value; + pos = 0; + while (PyDict_Next(w, &pos, &name, &value)) { + if (!PyString_Check(name) || + PyString_AsString(name)[0] == '_') + continue; + Py_INCREF(value); + err = PyDict_SetItem(locals, name, value); + Py_DECREF(value); + if (err != 0) + return -1; + } + return 0; + } + else { + x = PyDict_GetItem(w, name); + if (x == NULL) { + char buf[250]; + sprintf(buf, "cannot import name %.230s", + PyString_AsString(name)); + PyErr_SetString(PyExc_ImportError, buf); + return -1; + } + else + return PyDict_SetItem(locals, name, x); + } +} + +static PyObject * +build_class(methods, bases, name) + PyObject *methods; /* dictionary */ + PyObject *bases; /* tuple containing classes */ + PyObject *name; /* string */ +{ + int i, n; + if (!PyTuple_Check(bases)) { + PyErr_SetString(PyExc_SystemError, + "build_class with non-tuple bases"); + return NULL; + } + if (!PyDict_Check(methods)) { + PyErr_SetString(PyExc_SystemError, + "build_class with non-dictionary"); + return NULL; + } + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_SystemError, + "build_class witn non-string name"); + return NULL; + } + n = PyTuple_Size(bases); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + if (!PyClass_Check(base)) { + /* Call the base's *type*, if it is callable. + This code is a hook for Donald Beaudry's + and Jim Fulton's type extensions. In + unexended Python it will never be triggered + since its types are not callable. + Ditto: call the bases's *class*, if it has + one. This makes the same thing possible + without writing C code. A true meta-object + protocol! */ + PyObject *basetype = (PyObject *)base->ob_type; + PyObject *callable = NULL; + if (PyCallable_Check(basetype)) + callable = basetype; + else + callable = PyObject_GetAttrString( + base, "__class__"); + if (callable) { + PyObject *args; + PyObject *newclass = NULL; + args = Py_BuildValue( + "(OOO)", name, bases, methods); + if (args != NULL) { + newclass = PyEval_CallObject( + callable, args); + Py_DECREF(args); + } + if (callable != basetype) { + Py_DECREF(callable); + } + return newclass; + } + PyErr_SetString(PyExc_TypeError, + "base is not a class object"); + return NULL; + } + } + return PyClass_New(bases, methods, name); +} + +static int +exec_statement(f, prog, globals, locals) + PyFrameObject *f; + PyObject *prog; + PyObject *globals; + PyObject *locals; +{ + char *s; + int n; + PyObject *v; + int plain = 0; + + if (PyTuple_Check(prog) && globals == Py_None && locals == Py_None && + ((n = PyTuple_Size(prog)) == 2 || n == 3)) { + /* Backward compatibility hack */ + globals = PyTuple_GetItem(prog, 1); + if (n == 3) + locals = PyTuple_GetItem(prog, 2); + prog = PyTuple_GetItem(prog, 0); + } + if (globals == Py_None) { + globals = PyEval_GetGlobals(); + if (locals == Py_None) { + locals = PyEval_GetLocals(); + plain = 1; + } + } + else if (locals == Py_None) + locals = globals; + if (!PyString_Check(prog) && + !PyCode_Check(prog) && + !PyFile_Check(prog)) { + PyErr_SetString(PyExc_TypeError, + "exec 1st arg must be string, code or file object"); + return -1; + } + if (!PyDict_Check(globals) || !PyDict_Check(locals)) { + PyErr_SetString(PyExc_TypeError, + "exec 2nd/3rd args must be dict or None"); + return -1; + } + if (PyDict_GetItemString(globals, "__builtins__") == NULL) + PyDict_SetItemString(globals, "__builtins__", f->f_builtins); + if (PyCode_Check(prog)) { + v = PyEval_EvalCode((PyCodeObject *) prog, + globals, locals); + if (v == NULL) + return -1; + Py_DECREF(v); + return 0; + } + if (PyFile_Check(prog)) { + FILE *fp = PyFile_AsFile(prog); + char *name = PyString_AsString(PyFile_Name(prog)); + if (PyRun_File(fp, name, Py_file_input, + globals, locals) == NULL) + return -1; + return 0; + } + s = PyString_AsString(prog); + if ((int)strlen(s) != PyString_Size(prog)) { + PyErr_SetString(PyExc_ValueError, + "embedded '\\0' in exec string"); + return -1; + } + v = PyRun_String(s, Py_file_input, globals, locals); + if (v == NULL) + return -1; + Py_DECREF(v); + if (plain) + PyFrame_LocalsToFast(f, 0); + return 0; +} + +/* Hack for ni.py */ +static PyObject * +find_from_args(f, nexti) + PyFrameObject *f; + int nexti; +{ + int opcode; + int oparg; + PyObject *list, *name; + unsigned char *next_instr; + + _PyCode_GETCODEPTR(f->f_code, &next_instr); + next_instr += nexti; + + opcode = (*next_instr++); + if (opcode != IMPORT_FROM) { + Py_INCREF(Py_None); + return Py_None; + } + + list = PyList_New(0); + if (list == NULL) + return NULL; + + do { + oparg = (next_instr[1]<<8) + next_instr[0]; + next_instr += 2; + name = Getnamev(f, oparg); + if (PyList_Append(list, name) < 0) { + Py_DECREF(list); + break; + } + opcode = (*next_instr++); + } while (opcode == IMPORT_FROM); + + return list; +} + + +#ifdef DYNAMIC_EXECUTION_PROFILE + +PyObject * +getarray(a) + long a[256]; +{ + int i; + PyObject *l = PyList_New(256); + if (l == NULL) return NULL; + for (i = 0; i < 256; i++) { + PyObject *x = PyInt_FromLong(a[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + for (i = 0; i < 256; i++) + a[i] = 0; + return l; +} + +PyObject * +_Py_GetDXProfile(self, args) + PyObject *self, *args; +{ +#ifndef DXPAIRS + return getarray(dxp); +#else + int i; + PyObject *l = PyList_New(257); + if (l == NULL) return NULL; + for (i = 0; i < 257; i++) { + PyObject *x = getarray(dxpairs[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + return l; +#endif +} + +#endif diff --git a/src/main/resource/testFiles/cpython/revFiles/6a619f_46ab6d_Modules#posixmodule.c b/src/main/resource/testFiles/cpython/revFiles/6a619f_46ab6d_Modules#posixmodule.c new file mode 100644 index 0000000..947e169 --- /dev/null +++ b/src/main/resource/testFiles/cpython/revFiles/6a619f_46ab6d_Modules#posixmodule.c @@ -0,0 +1,3503 @@ +/*********************************************************** +Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, +The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI or Corporation for National Research Initiatives or +CNRI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +While CWI is the initial source for this software, a modified version +is made available by the Corporation for National Research Initiatives +(CNRI) at the Internet address ftp://ftp.python.org. + +STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH +CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* POSIX module implementation */ + +/* This file is also used for Windows NT and MS-Win. In that case the module + actually calls itself 'nt', not 'posix', and a few functions are + either unimplemented or implemented differently. The source + assumes that for Windows NT, the macro 'MS_WIN32' is defined independent + of the compiler used. Different compilers define their own feature + test macro, e.g. '__BORLANDC__' or '_MSC_VER'. */ + +/* See also ../Dos/dosmodule.c */ + +static char posix__doc__ [] = +"This module provides access to operating system functionality that is\n\ +standardized by the C Standard and the POSIX standard (a thinly\n\ +disguised Unix interface). Refer to the library manual and\n\ +corresponding Unix manual entries for more information on calls."; + +#include "Python.h" + +#if defined(PYOS_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_DOSPROCESS +#define INCL_NOPMAPI +#include +#endif + +#include +#include +#ifdef HAVE_SYS_WAIT_H +#include /* For WNOHANG */ +#endif + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#include "mytime.h" /* For clock_t on some systems */ + +#ifdef HAVE_FCNTL_H +#include +#endif /* HAVE_FCNTL_H */ + +/* Various compilers have only certain posix functions */ +/* XXX Gosh I wish these were all moved into config.h */ +#if defined(PYCC_VACPP) && defined(PYOS_OS2) +#include +#else +#if defined(__WATCOMC__) && !defined(__QNX__) /* Watcom compiler */ +#define HAVE_GETCWD 1 +#define HAVE_OPENDIR 1 +#define HAVE_SYSTEM 1 +#if defined(__OS2__) +#define HAVE_EXECV 1 +#define HAVE_WAIT 1 +#endif +#include +#else +#ifdef __BORLANDC__ /* Borland compiler */ +#define HAVE_EXECV 1 +#define HAVE_GETCWD 1 +#define HAVE_GETEGID 1 +#define HAVE_GETEUID 1 +#define HAVE_GETGID 1 +#define HAVE_GETPPID 1 +#define HAVE_GETUID 1 +#define HAVE_KILL 1 +#define HAVE_OPENDIR 1 +#define HAVE_PIPE 1 +#define HAVE_POPEN 1 +#define HAVE_SYSTEM 1 +#define HAVE_WAIT 1 +#else +#ifdef _MSC_VER /* Microsoft compiler */ +#define HAVE_GETCWD 1 +#ifdef MS_WIN32 +#define HAVE_SPAWNV 1 +#define HAVE_EXECV 1 +#define HAVE_PIPE 1 +#define HAVE_POPEN 1 +#define HAVE_SYSTEM 1 +#else /* 16-bit Windows */ +#endif /* !MS_WIN32 */ +#else /* all other compilers */ +/* Unix functions that the configure script doesn't check for */ +#define HAVE_EXECV 1 +#define HAVE_FORK 1 +#define HAVE_GETCWD 1 +#define HAVE_GETEGID 1 +#define HAVE_GETEUID 1 +#define HAVE_GETGID 1 +#define HAVE_GETPPID 1 +#define HAVE_GETUID 1 +#define HAVE_KILL 1 +#define HAVE_OPENDIR 1 +#define HAVE_PIPE 1 +#define HAVE_POPEN 1 +#define HAVE_SYSTEM 1 +#define HAVE_WAIT 1 +#define HAVE_TTYNAME 1 +#endif /* _MSC_VER */ +#endif /* __BORLANDC__ */ +#endif /* ! __WATCOMC__ || __QNX__ */ +#endif /* ! __IBMC__ */ + +#ifndef _MSC_VER + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef NeXT +/* NeXT's and aren't worth much */ +#undef HAVE_UNISTD_H +#undef HAVE_UTIME_H +#define HAVE_WAITPID +/* #undef HAVE_GETCWD */ +#define UNION_WAIT /* This should really be checked for by autoconf */ +#endif + +#ifdef HAVE_UNISTD_H +/* XXX These are for SunOS4.1.3 but shouldn't hurt elsewhere */ +extern int rename(); +extern int pclose(); +extern int lstat(); +extern int symlink(); +extern int fsync(); +#else /* !HAVE_UNISTD_H */ +#if defined(PYCC_VACPP) +extern int mkdir Py_PROTO((char *)); +#else +#if ( defined(__WATCOMC__) || defined(_MSC_VER) ) && !defined(__QNX__) +extern int mkdir Py_PROTO((const char *)); +#else +extern int mkdir Py_PROTO((const char *, mode_t)); +#endif +#endif +#if defined(__IBMC__) || defined(__IBMCPP__) +extern int chdir Py_PROTO((char *)); +extern int rmdir Py_PROTO((char *)); +#else +extern int chdir Py_PROTO((const char *)); +extern int rmdir Py_PROTO((const char *)); +#endif +extern int chmod Py_PROTO((const char *, mode_t)); +extern int chown Py_PROTO((const char *, uid_t, gid_t)); +extern char *getcwd Py_PROTO((char *, int)); +extern char *strerror Py_PROTO((int)); +extern int link Py_PROTO((const char *, const char *)); +extern int rename Py_PROTO((const char *, const char *)); +extern int stat Py_PROTO((const char *, struct stat *)); +extern int unlink Py_PROTO((const char *)); +extern int pclose Py_PROTO((FILE *)); +#ifdef HAVE_SYMLINK +extern int symlink Py_PROTO((const char *, const char *)); +#endif /* HAVE_SYMLINK */ +#ifdef HAVE_LSTAT +extern int lstat Py_PROTO((const char *, struct stat *)); +#endif /* HAVE_LSTAT */ +#endif /* !HAVE_UNISTD_H */ + +#endif /* !_MSC_VER */ + +#ifdef HAVE_UTIME_H +#include +#endif /* HAVE_UTIME_H */ + +#ifdef HAVE_SYS_UTIME_H +#include +#define HAVE_UTIME_H /* pretend we do for the rest of this file */ +#endif /* HAVE_SYS_UTIME_H */ + +#ifdef HAVE_SYS_TIMES_H +#include +#endif /* HAVE_SYS_TIMES_H */ + +#ifdef HAVE_SYS_PARAM_H +#include +#endif /* HAVE_SYS_PARAM_H */ + +#ifdef HAVE_SYS_UTSNAME_H +#include +#endif /* HAVE_SYS_UTSNAME_H */ + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif /* MAXPATHLEN */ + +#ifdef HAVE_DIRENT_H +#include +#define NAMLEN(dirent) strlen((dirent)->d_name) +#else +#if defined(__WATCOMC__) && !defined(__QNX__) +#include +#define NAMLEN(dirent) strlen((dirent)->d_name) +#else +#define dirent direct +#define NAMLEN(dirent) (dirent)->d_namlen +#endif +#ifdef HAVE_SYS_NDIR_H +#include +#endif +#ifdef HAVE_SYS_DIR_H +#include +#endif +#ifdef HAVE_NDIR_H +#include +#endif +#endif + +#ifdef _MSC_VER +#include +#include +#include +#include +#ifdef MS_WIN32 +#define popen _popen +#define pclose _pclose +#else /* 16-bit Windows */ +#include +#include +#endif /* MS_WIN32 */ +#endif /* _MSC_VER */ + +#if defined(PYCC_VACPP) && defined(PYOS_OS2) +#include +#endif /* OS2 */ + +#ifdef UNION_WAIT +/* Emulate some macros on systems that have a union instead of macros */ + +#ifndef WIFEXITED +#define WIFEXITED(u_wait) (!(u_wait).w_termsig && !(u_wait).w_coredump) +#endif + +#ifndef WEXITSTATUS +#define WEXITSTATUS(u_wait) (WIFEXITED(u_wait)?((u_wait).w_retcode):-1) +#endif + +#ifndef WTERMSIG +#define WTERMSIG(u_wait) ((u_wait).w_termsig) +#endif + +#endif /* UNION_WAIT */ + +/* Return a dictionary corresponding to the POSIX environment table */ + +#if !defined(_MSC_VER) && ( !defined(__WATCOMC__) || defined(__QNX__) ) +extern char **environ; +#endif /* !_MSC_VER */ + +static PyObject * +convertenviron() +{ + PyObject *d; + char **e; + d = PyDict_New(); + if (d == NULL) + return NULL; + if (environ == NULL) + return d; + /* This part ignores errors */ + for (e = environ; *e != NULL; e++) { + PyObject *k; + PyObject *v; + char *p = strchr(*e, '='); + if (p == NULL) + continue; + k = PyString_FromStringAndSize(*e, (int)(p-*e)); + if (k == NULL) { + PyErr_Clear(); + continue; + } + v = PyString_FromString(p+1); + if (v == NULL) { + PyErr_Clear(); + Py_DECREF(k); + continue; + } + if (PyDict_GetItem(d, k) == NULL) { + if (PyDict_SetItem(d, k, v) != 0) + PyErr_Clear(); + } + Py_DECREF(k); + Py_DECREF(v); + } +#if defined(PYOS_OS2) + { + APIRET rc; + char buffer[1024]; /* OS/2 Provides a Documented Max of 1024 Chars */ + + rc = DosQueryExtLIBPATH(buffer, BEGIN_LIBPATH); + if (rc == NO_ERROR) { /* (not a type, envname is NOT 'BEGIN_LIBPATH') */ + PyObject *v = PyString_FromString(buffer); + PyDict_SetItemString(d, "BEGINLIBPATH", v); + Py_DECREF(v); + } + rc = DosQueryExtLIBPATH(buffer, END_LIBPATH); + if (rc == NO_ERROR) { /* (not a typo, envname is NOT 'END_LIBPATH') */ + PyObject *v = PyString_FromString(buffer); + PyDict_SetItemString(d, "ENDLIBPATH", v); + Py_DECREF(v); + } + } +#endif + return d; +} + + +/* Set a POSIX-specific error from errno, and return NULL */ + +static PyObject * +posix_error() +{ + return PyErr_SetFromErrno(PyExc_OSError); +} +static PyObject * +posix_error_with_filename(name) + char* name; +{ + return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); +} + + +#if defined(PYOS_OS2) +/********************************************************************** + * Helper Function to Trim and Format OS/2 Messages + **********************************************************************/ + static void +os2_formatmsg(char *msgbuf, int msglen, char *reason) +{ + msgbuf[msglen] = '\0'; /* OS/2 Doesn't Guarantee a Terminator */ + + if (strlen(msgbuf) > 0) { /* If Non-Empty Msg, Trim CRLF */ + char *lastc = &msgbuf[ strlen(msgbuf)-1 ]; + + while (lastc > msgbuf && isspace(*lastc)) + *lastc-- = '\0'; /* Trim Trailing Whitespace (CRLF) */ + } + + /* Add Optional Reason Text */ + if (reason) { + strcat(msgbuf, " : "); + strcat(msgbuf, reason); + } +} + +/********************************************************************** + * Decode an OS/2 Operating System Error Code + * + * A convenience function to lookup an OS/2 error code and return a + * text message we can use to raise a Python exception. + * + * Notes: + * The messages for errors returned from the OS/2 kernel reside in + * the file OSO001.MSG in the \OS2 directory hierarchy. + * + **********************************************************************/ + static char * +os2_strerror(char *msgbuf, int msgbuflen, int errorcode, char *reason) +{ + APIRET rc; + ULONG msglen; + + /* Retrieve Kernel-Related Error Message from OSO001.MSG File */ + Py_BEGIN_ALLOW_THREADS + rc = DosGetMessage(NULL, 0, msgbuf, msgbuflen, + errorcode, "oso001.msg", &msglen); + Py_END_ALLOW_THREADS + + if (rc == NO_ERROR) + os2_formatmsg(msgbuf, msglen, reason); + else + sprintf(msgbuf, "unknown OS error #%d", errorcode); + + return msgbuf; +} + +/* Set an OS/2-specific error and return NULL. OS/2 kernel + errors are not in a global variable e.g. 'errno' nor are + they congruent with posix error numbers. */ + +static PyObject * os2_error(int code) +{ + char text[1024]; + PyObject *v; + + os2_strerror(text, sizeof(text), code, ""); + + v = Py_BuildValue("(is)", code, text); + if (v != NULL) { + PyErr_SetObject(PyExc_OSError, v); + Py_DECREF(v); + } + return NULL; /* Signal to Python that an Exception is Pending */ +} + +#endif /* OS2 */ + +/* POSIX generic methods */ + +static PyObject * +posix_int(args, func) + PyObject *args; + int (*func) Py_FPROTO((int)); +{ + int fd; + int res; + if (!PyArg_Parse(args, "i", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(fd); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +posix_1str(args, func) + PyObject *args; + int (*func) Py_FPROTO((const char *)); +{ + char *path1; + int res; + if (!PyArg_Parse(args, "s", &path1)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(path1); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_filename(path1); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +posix_2str(args, func) + PyObject *args; + int (*func) Py_FPROTO((const char *, const char *)); +{ + char *path1, *path2; + int res; + if (!PyArg_Parse(args, "(ss)", &path1, &path2)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(path1, path2); + Py_END_ALLOW_THREADS + if (res != 0) + /* XXX how to report both path1 and path2??? */ + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +posix_strint(args, func) + PyObject *args; + int (*func) Py_FPROTO((const char *, int)); +{ + char *path; + int i; + int res; + if (!PyArg_Parse(args, "(si)", &path, &i)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(path, i); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_filename(path); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +posix_strintint(args, func) + PyObject *args; + int (*func) Py_FPROTO((const char *, int, int)); +{ + char *path; + int i,i2; + int res; + if (!PyArg_Parse(args, "(sii)", &path, &i, &i2)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(path, i, i2); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_filename(path); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +posix_do_stat(self, args, statfunc) + PyObject *self; + PyObject *args; + int (*statfunc) Py_FPROTO((const char *, struct stat *)); +{ + struct stat st; + char *path; + int res; + if (!PyArg_Parse(args, "s", &path)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*statfunc)(path, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error_with_filename(path); +#if !defined(HAVE_LARGEFILE_SUPPORT) + return Py_BuildValue("(llllllllll)", + (long)st.st_mode, + (long)st.st_ino, + (long)st.st_dev, + (long)st.st_nlink, + (long)st.st_uid, + (long)st.st_gid, + (long)st.st_size, + (long)st.st_atime, + (long)st.st_mtime, + (long)st.st_ctime); +#else + return Py_BuildValue("(lLllllLlll)", + (long)st.st_mode, + (LONG_LONG)st.st_ino, + (long)st.st_dev, + (long)st.st_nlink, + (long)st.st_uid, + (long)st.st_gid, + (LONG_LONG)st.st_size, + (long)st.st_atime, + (long)st.st_mtime, + (long)st.st_ctime); +#endif +} + + +/* POSIX methods */ + +static char posix_access__doc__[] = +"access(path, mode) -> 1 if granted, 0 otherwise\n\ +Test for access to a file."; + +static PyObject * +posix_access(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + int mode; + int res; + + if (!PyArg_Parse(args, "(si)", &path, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = access(path, mode); + Py_END_ALLOW_THREADS + return(PyInt_FromLong(res == 0 ? 1L : 0L)); +} + +#ifndef F_OK +#define F_OK 0 +#endif +#ifndef R_OK +#define R_OK 4 +#endif +#ifndef W_OK +#define W_OK 2 +#endif +#ifndef X_OK +#define X_OK 1 +#endif + +#ifdef HAVE_TTYNAME +static char posix_ttyname__doc__[] = +"ttyname(fd) -> String\n\ +Return the name of the terminal device connected to 'fd'."; + +static PyObject * +posix_ttyname(self, args) + PyObject *self; + PyObject *args; +{ + PyObject *file; + int id; + char *ret; + + if (!PyArg_Parse(args, "i", &id)) + return NULL; + + ret = ttyname(id); + if (ret == NULL) + return(posix_error()); + return(PyString_FromString(ret)); +} +#endif + +static char posix_chdir__doc__[] = +"chdir(path) -> None\n\ +Change the current working directory to the specified path."; + +static PyObject * +posix_chdir(self, args) + PyObject *self; + PyObject *args; +{ + return posix_1str(args, chdir); +} + + +static char posix_chmod__doc__[] = +"chmod(path, mode) -> None\n\ +Change the access permissions of a file."; + +static PyObject * +posix_chmod(self, args) + PyObject *self; + PyObject *args; +{ + return posix_strint(args, chmod); +} + + +#ifdef HAVE_FSYNC +static char posix_fsync__doc__[] = +"fsync(fildes) -> None\n\ +force write of file with filedescriptor to disk."; + +static PyObject * +posix_fsync(self, args) + PyObject *self; + PyObject *args; +{ + return posix_int(args, fsync); +} +#endif /* HAVE_FSYNC */ + +#ifdef HAVE_FDATASYNC +static char posix_fdatasync__doc__[] = +"fdatasync(fildes) -> None\n\ +force write of file with filedescriptor to disk.\n\ + does not force update of metadata."; + +extern int fdatasync(int); /* Prototype just in case */ + +static PyObject * +posix_fdatasync(self, args) + PyObject *self; + PyObject *args; +{ + return posix_int(args, fdatasync); +} +#endif /* HAVE_FDATASYNC */ + + +#ifdef HAVE_CHOWN +static char posix_chown__doc__[] = +"chown(path, uid, gid) -> None\n\ +Change the owner and group id of path to the numeric uid and gid."; + +static PyObject * +posix_chown(self, args) + PyObject *self; + PyObject *args; +{ + return posix_strintint(args, chown); +} +#endif /* HAVE_CHOWN */ + + +#ifdef HAVE_GETCWD +static char posix_getcwd__doc__[] = +"getcwd() -> path\n\ +Return a string representing the current working directory."; + +static PyObject * +posix_getcwd(self, args) + PyObject *self; + PyObject *args; +{ + char buf[1026]; + char *res; + if (!PyArg_NoArgs(args)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = getcwd(buf, sizeof buf); + Py_END_ALLOW_THREADS + if (res == NULL) + return posix_error(); + return PyString_FromString(buf); +} +#endif + + +#ifdef HAVE_LINK +static char posix_link__doc__[] = +"link(src, dst) -> None\n\ +Create a hard link to a file."; + +static PyObject * +posix_link(self, args) + PyObject *self; + PyObject *args; +{ + return posix_2str(args, link); +} +#endif /* HAVE_LINK */ + + +static char posix_listdir__doc__[] = +"listdir(path) -> list_of_strings\n\ +Return a list containing the names of the entries in the directory.\n\ +\n\ + path: path of directory to list\n\ +\n\ +The list is in arbitrary order. It does not include the special\n\ +entries '.' and '..' even if they are present in the directory."; + +static PyObject * +posix_listdir(self, args) + PyObject *self; + PyObject *args; +{ + /* XXX Should redo this putting the (now four) versions of opendir + in separate files instead of having them all here... */ +#if defined(MS_WIN32) && !defined(HAVE_OPENDIR) + + char *name; + int len; + PyObject *d, *v; + HANDLE hFindFile; + WIN32_FIND_DATA FileData; + char namebuf[MAX_PATH+5]; + + if (!PyArg_Parse(args, "t#", &name, &len)) + return NULL; + if (len >= MAX_PATH) { + PyErr_SetString(PyExc_ValueError, "path too long"); + return NULL; + } + strcpy(namebuf, name); + if (namebuf[len-1] != '/' && namebuf[len-1] != '\\') + namebuf[len++] = '/'; + strcpy(namebuf + len, "*.*"); + + if ((d = PyList_New(0)) == NULL) + return NULL; + + hFindFile = FindFirstFile(namebuf, &FileData); + if (hFindFile == INVALID_HANDLE_VALUE) { + errno = GetLastError(); + if (errno == ERROR_FILE_NOT_FOUND) + return PyList_New(0); + return posix_error_with_filename(name); + } + do { + if (FileData.cFileName[0] == '.' && + (FileData.cFileName[1] == '\0' || + FileData.cFileName[1] == '.' && + FileData.cFileName[2] == '\0')) + continue; + v = PyString_FromString(FileData.cFileName); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } while (FindNextFile(hFindFile, &FileData) == TRUE); + + if (FindClose(hFindFile) == FALSE) { + errno = GetLastError(); + return posix_error_with_filename(&name); + } + + return d; + +#else /* !MS_WIN32 */ +#ifdef _MSC_VER /* 16-bit Windows */ + +#ifndef MAX_PATH +#define MAX_PATH 250 +#endif + char *name, *pt; + int len; + PyObject *d, *v; + char namebuf[MAX_PATH+5]; + struct _find_t ep; + + if (!PyArg_Parse(args, "t#", &name, &len)) + return NULL; + if (len >= MAX_PATH) { + PyErr_SetString(PyExc_ValueError, "path too long"); + return NULL; + } + strcpy(namebuf, name); + for (pt = namebuf; *pt; pt++) + if (*pt == '/') + *pt = '\\'; + if (namebuf[len-1] != '\\') + namebuf[len++] = '\\'; + strcpy(namebuf + len, "*.*"); + + if ((d = PyList_New(0)) == NULL) + return NULL; + + if (_dos_findfirst(namebuf, _A_RDONLY | + _A_HIDDEN | _A_SYSTEM | _A_SUBDIR, &ep) != 0) + { + errno = ENOENT; + return posix_error_with_filename(name); + } + do { + if (ep.name[0] == '.' && + (ep.name[1] == '\0' || + ep.name[1] == '.' && + ep.name[2] == '\0')) + continue; + strcpy(namebuf, ep.name); + for (pt = namebuf; *pt; pt++) + if (isupper(*pt)) + *pt = tolower(*pt); + v = PyString_FromString(namebuf); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } while (_dos_findnext(&ep) == 0); + + return d; + +#else +#if defined(PYOS_OS2) + +#ifndef MAX_PATH +#define MAX_PATH CCHMAXPATH +#endif + char *name, *pt; + int len; + PyObject *d, *v; + char namebuf[MAX_PATH+5]; + HDIR hdir = 1; + ULONG srchcnt = 1; + FILEFINDBUF3 ep; + APIRET rc; + + if (!PyArg_Parse(args, "t#", &name, &len)) + return NULL; + if (len >= MAX_PATH) { + PyErr_SetString(PyExc_ValueError, "path too long"); + return NULL; + } + strcpy(namebuf, name); + for (pt = namebuf; *pt; pt++) + if (*pt == '/') + *pt = '\\'; + if (namebuf[len-1] != '\\') + namebuf[len++] = '\\'; + strcpy(namebuf + len, "*.*"); + + if ((d = PyList_New(0)) == NULL) + return NULL; + + rc = DosFindFirst(namebuf, /* Wildcard Pattern to Match */ + &hdir, /* Handle to Use While Search Directory */ + FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY, + &ep, sizeof(ep), /* Structure to Receive Directory Entry */ + &srchcnt, /* Max and Actual Count of Entries Per Iteration */ + FIL_STANDARD); /* Format of Entry (EAs or Not) */ + + if (rc != NO_ERROR) { + errno = ENOENT; + return posix_error_with_filename(name); + } + + if (srchcnt > 0) { /* If Directory is NOT Totally Empty, */ + do { + if (ep.achName[0] == '.' + && (ep.achName[1] == '\0' || ep.achName[1] == '.' && ep.achName[2] == '\0')) + continue; /* Skip Over "." and ".." Names */ + + strcpy(namebuf, ep.achName); + + /* Leave Case of Name Alone -- In Native Form */ + /* (Removed Forced Lowercasing Code) */ + + v = PyString_FromString(namebuf); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } while (DosFindNext(hdir, &ep, sizeof(ep), &srchcnt) == NO_ERROR && srchcnt > 0); + } + + return d; +#else + + char *name; + PyObject *d, *v; + DIR *dirp; + struct dirent *ep; + if (!PyArg_Parse(args, "s", &name)) + return NULL; + Py_BEGIN_ALLOW_THREADS + if ((dirp = opendir(name)) == NULL) { + Py_BLOCK_THREADS + return posix_error_with_filename(name); + } + if ((d = PyList_New(0)) == NULL) { + closedir(dirp); + Py_BLOCK_THREADS + return NULL; + } + while ((ep = readdir(dirp)) != NULL) { + if (ep->d_name[0] == '.' && + (NAMLEN(ep) == 1 || + (ep->d_name[1] == '.' && NAMLEN(ep) == 2))) + continue; + v = PyString_FromStringAndSize(ep->d_name, NAMLEN(ep)); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } + closedir(dirp); + Py_END_ALLOW_THREADS + + return d; + +#endif /* !PYOS_OS2 */ +#endif /* !_MSC_VER */ +#endif /* !MS_WIN32 */ +} + +static char posix_mkdir__doc__[] = +"mkdir(path [, mode=0777]) -> None\n\ +Create a directory."; + +static PyObject * +posix_mkdir(self, args) + PyObject *self; + PyObject *args; +{ + int res; + char *path; + int mode = 0777; + if (!PyArg_ParseTuple(args, "s|i", &path, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS +#if ( defined(__WATCOMC__) || defined(_MSC_VER) || defined(PYCC_VACPP) ) && !defined(__QNX__) + res = mkdir(path); +#else + res = mkdir(path, mode); +#endif + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_filename(path); + Py_INCREF(Py_None); + return Py_None; +} + + +#ifdef HAVE_NICE +static char posix_nice__doc__[] = +"nice(inc) -> new_priority\n\ +Decrease the priority of process and return new priority."; + +static PyObject * +posix_nice(self, args) + PyObject *self; + PyObject *args; +{ + int increment, value; + + if (!PyArg_Parse(args, "i", &increment)) + return NULL; + value = nice(increment); + if (value == -1) + return posix_error(); + return PyInt_FromLong((long) value); +} +#endif /* HAVE_NICE */ + + +static char posix_rename__doc__[] = +"rename(old, new) -> None\n\ +Rename a file or directory."; + +static PyObject * +posix_rename(self, args) + PyObject *self; + PyObject *args; +{ + return posix_2str(args, rename); +} + + +static char posix_rmdir__doc__[] = +"rmdir(path) -> None\n\ +Remove a directory."; + +static PyObject * +posix_rmdir(self, args) + PyObject *self; + PyObject *args; +{ + return posix_1str(args, rmdir); +} + + +static char posix_stat__doc__[] = +"stat(path) -> (mode,ino,dev,nlink,uid,gid,size,atime,mtime,ctime)\n\ +Perform a stat system call on the given path."; + +static PyObject * +posix_stat(self, args) + PyObject *self; + PyObject *args; +{ + return posix_do_stat(self, args, stat); +} + + +#ifdef HAVE_SYSTEM +static char posix_system__doc__[] = +"system(command) -> exit_status\n\ +Execute the command (a string) in a subshell."; + +static PyObject * +posix_system(self, args) + PyObject *self; + PyObject *args; +{ + char *command; + long sts; + if (!PyArg_Parse(args, "s", &command)) + return NULL; + Py_BEGIN_ALLOW_THREADS + sts = system(command); + Py_END_ALLOW_THREADS + return PyInt_FromLong(sts); +} +#endif + + +static char posix_umask__doc__[] = +"umask(new_mask) -> old_mask\n\ +Set the current numeric umask and return the previous umask."; + +static PyObject * +posix_umask(self, args) + PyObject *self; + PyObject *args; +{ + int i; + if (!PyArg_Parse(args, "i", &i)) + return NULL; + i = umask(i); + if (i < 0) + return posix_error(); + return PyInt_FromLong((long)i); +} + + +static char posix_unlink__doc__[] = +"unlink(path) -> None\n\ +Remove a file (same as remove(path))."; + +static char posix_remove__doc__[] = +"remove(path) -> None\n\ +Remove a file (same as unlink(path))."; + +static PyObject * +posix_unlink(self, args) + PyObject *self; + PyObject *args; +{ + return posix_1str(args, unlink); +} + + +#ifdef HAVE_UNAME +static char posix_uname__doc__[] = +"uname() -> (sysname, nodename, release, version, machine)\n\ +Return a tuple identifying the current operating system."; + +static PyObject * +posix_uname(self, args) + PyObject *self; + PyObject *args; +{ + struct utsname u; + int res; + if (!PyArg_NoArgs(args)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = uname(&u); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + return Py_BuildValue("(sssss)", + u.sysname, + u.nodename, + u.release, + u.version, + u.machine); +} +#endif /* HAVE_UNAME */ + + +static char posix_utime__doc__[] = +"utime(path, (atime, utime)) -> None\n\ +Set the access and modified time of the file to the given values."; + +static PyObject * +posix_utime(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + long atime, mtime; + int res; + +/* XXX should define struct utimbuf instead, above */ +#ifdef HAVE_UTIME_H + struct utimbuf buf; +#define ATIME buf.actime +#define MTIME buf.modtime +#define UTIME_ARG &buf +#else /* HAVE_UTIME_H */ + time_t buf[2]; +#define ATIME buf[0] +#define MTIME buf[1] +#define UTIME_ARG buf +#endif /* HAVE_UTIME_H */ + + if (!PyArg_Parse(args, "(s(ll))", &path, &atime, &mtime)) + return NULL; + ATIME = atime; + MTIME = mtime; + Py_BEGIN_ALLOW_THREADS + res = utime(path, UTIME_ARG); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_filename(path); + Py_INCREF(Py_None); + return Py_None; +#undef UTIME_ARG +#undef ATIME +#undef MTIME +} + + +/* Process operations */ + +static char posix__exit__doc__[] = +"_exit(status)\n\ +Exit to the system with specified status, without normal exit processing."; + +static PyObject * +posix__exit(self, args) + PyObject *self; + PyObject *args; +{ + int sts; + if (!PyArg_Parse(args, "i", &sts)) + return NULL; + _exit(sts); + return NULL; /* Make gcc -Wall happy */ +} + + +#ifdef HAVE_EXECV +static char posix_execv__doc__[] = +"execv(path, args)\n\ +Execute an executable path with arguments, replacing current process.\n\ +\n\ + path: path of executable file\n\ + args: tuple or list of strings"; + +static PyObject * +posix_execv(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + PyObject *argv; + char **argvlist; + int i, argc; + PyObject *(*getitem) Py_PROTO((PyObject *, int)); + + /* execv has two arguments: (path, argv), where + argv is a list or tuple of strings. */ + + if (!PyArg_Parse(args, "(sO)", &path, &argv)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + badarg: + PyErr_BadArgument(); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) + return NULL; + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), "s", &argvlist[i])) { + PyMem_DEL(argvlist); + goto badarg; + } + } + argvlist[argc] = NULL; + +#ifdef BAD_EXEC_PROTOTYPES + execv(path, (const char **) argvlist); +#else /* BAD_EXEC_PROTOTYPES */ + execv(path, argvlist); +#endif /* BAD_EXEC_PROTOTYPES */ + + /* If we get here it's definitely an error */ + + PyMem_DEL(argvlist); + return posix_error(); +} + + +static char posix_execve__doc__[] = +"execve(path, args, env)\n\ +Execute a path with arguments and environment, replacing current process.\n\ +\n\ + path: path of executable file\n\ + args: tuple or list of arguments\n\ + env: dictonary of strings mapping to strings"; + +static PyObject * +posix_execve(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + PyObject *argv, *env; + char **argvlist; + char **envlist; + PyObject *key, *val, *keys=NULL, *vals=NULL; + int i, pos, argc, envc; + PyObject *(*getitem) Py_PROTO((PyObject *, int)); + + /* execve has three arguments: (path, argv, env), where + argv is a list or tuple of strings and env is a dictionary + like posix.environ. */ + + if (!PyArg_Parse(args, "(sOO)", &path, &argv, &env)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + PyErr_SetString(PyExc_TypeError, "argv must be tuple or list"); + return NULL; + } + if (!PyMapping_Check(env)) { + PyErr_SetString(PyExc_TypeError, "env must be mapping object"); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) { + PyErr_NoMemory(); + return NULL; + } + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), + "s;argv must be list of strings", + &argvlist[i])) + { + goto fail_1; + } + } + argvlist[argc] = NULL; + + i = PyMapping_Length(env); + envlist = PyMem_NEW(char *, i + 1); + if (envlist == NULL) { + PyErr_NoMemory(); + goto fail_1; + } + envc = 0; + keys = PyMapping_Keys(env); + vals = PyMapping_Values(env); + if (!keys || !vals) + goto fail_2; + + for (pos = 0; pos < i; pos++) { + char *p, *k, *v; + + key = PyList_GetItem(keys, pos); + val = PyList_GetItem(vals, pos); + if (!key || !val) + goto fail_2; + + if (!PyArg_Parse(key, "s;non-string key in env", &k) || + !PyArg_Parse(val, "s;non-string value in env", &v)) + { + goto fail_2; + } + +#if defined(PYOS_OS2) + /* Omit Pseudo-Env Vars that Would Confuse Programs if Passed On */ + if (stricmp(k, "BEGINLIBPATH") != 0 && stricmp(k, "ENDLIBPATH") != 0) { +#endif + p = PyMem_NEW(char, PyString_Size(key)+PyString_Size(val) + 2); + if (p == NULL) { + PyErr_NoMemory(); + goto fail_2; + } + sprintf(p, "%s=%s", k, v); + envlist[envc++] = p; +#if defined(PYOS_OS2) + } +#endif + } + envlist[envc] = 0; + + +#ifdef BAD_EXEC_PROTOTYPES + execve(path, (const char **)argvlist, envlist); +#else /* BAD_EXEC_PROTOTYPES */ + execve(path, argvlist, envlist); +#endif /* BAD_EXEC_PROTOTYPES */ + + /* If we get here it's definitely an error */ + + (void) posix_error(); + + fail_2: + while (--envc >= 0) + PyMem_DEL(envlist[envc]); + PyMem_DEL(envlist); + fail_1: + PyMem_DEL(argvlist); + Py_XDECREF(vals); + Py_XDECREF(keys); + return NULL; +} +#endif /* HAVE_EXECV */ + + +#ifdef HAVE_SPAWNV +static char posix_spawnv__doc__[] = +"spawnv(mode, path, args)\n\ +Execute an executable path with arguments, replacing current process.\n\ +\n\ + mode: mode of process creation\n\ + path: path of executable file\n\ + args: tuple or list of strings"; + +static PyObject * +posix_spawnv(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + PyObject *argv; + char **argvlist; + int mode, i, argc; + PyObject *(*getitem) Py_PROTO((PyObject *, int)); + + /* spawnv has three arguments: (mode, path, argv), where + argv is a list or tuple of strings. */ + + if (!PyArg_Parse(args, "(isO)", &mode, &path, &argv)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + badarg: + PyErr_BadArgument(); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) + return NULL; + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), "s", &argvlist[i])) { + PyMem_DEL(argvlist); + goto badarg; + } + } + argvlist[argc] = NULL; + + if (mode == _OLD_P_OVERLAY) + mode = _P_OVERLAY; + i = _spawnv(mode, path, argvlist); + + PyMem_DEL(argvlist); + + if (i == -1) + return posix_error(); + else + return Py_BuildValue("i", i); +} + + +static char posix_spawnve__doc__[] = +"spawnve(mode, path, args, env)\n\ +Execute a path with arguments and environment, replacing current process.\n\ +\n\ + mode: mode of process creation\n\ + path: path of executable file\n\ + args: tuple or list of arguments\n\ + env: dictonary of strings mapping to strings"; + +static PyObject * +posix_spawnve(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + PyObject *argv, *env; + char **argvlist; + char **envlist; + PyObject *key, *val, *keys=NULL, *vals=NULL, *res=NULL; + int mode, i, pos, argc, envc; + PyObject *(*getitem) Py_PROTO((PyObject *, int)); + + /* spawnve has four arguments: (mode, path, argv, env), where + argv is a list or tuple of strings and env is a dictionary + like posix.environ. */ + + if (!PyArg_Parse(args, "(isOO)", &mode, &path, &argv, &env)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + PyErr_SetString(PyExc_TypeError, "argv must be tuple or list"); + return NULL; + } + if (!PyMapping_Check(env)) { + PyErr_SetString(PyExc_TypeError, "env must be mapping object"); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) { + PyErr_NoMemory(); + return NULL; + } + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), + "s;argv must be list of strings", + &argvlist[i])) + { + goto fail_1; + } + } + argvlist[argc] = NULL; + + i = PyMapping_Length(env); + envlist = PyMem_NEW(char *, i + 1); + if (envlist == NULL) { + PyErr_NoMemory(); + goto fail_1; + } + envc = 0; + keys = PyMapping_Keys(env); + vals = PyMapping_Values(env); + if (!keys || !vals) + goto fail_2; + + for (pos = 0; pos < i; pos++) { + char *p, *k, *v; + + key = PyList_GetItem(keys, pos); + val = PyList_GetItem(vals, pos); + if (!key || !val) + goto fail_2; + + if (!PyArg_Parse(key, "s;non-string key in env", &k) || + !PyArg_Parse(val, "s;non-string value in env", &v)) + { + goto fail_2; + } + p = PyMem_NEW(char, PyString_Size(key)+PyString_Size(val) + 2); + if (p == NULL) { + PyErr_NoMemory(); + goto fail_2; + } + sprintf(p, "%s=%s", k, v); + envlist[envc++] = p; + } + envlist[envc] = 0; + + if (mode == _OLD_P_OVERLAY) + mode = _P_OVERLAY; + i = _spawnve(mode, path, argvlist, envlist); + if (i == -1) + (void) posix_error(); + else + res = Py_BuildValue("i", i); + + fail_2: + while (--envc >= 0) + PyMem_DEL(envlist[envc]); + PyMem_DEL(envlist); + fail_1: + PyMem_DEL(argvlist); + Py_XDECREF(vals); + Py_XDECREF(keys); + return res; +} +#endif /* HAVE_SPAWNV */ + + +#ifdef HAVE_FORK +static char posix_fork__doc__[] = +"fork() -> pid\n\ +Fork a child process.\n\ +\n\ +Return 0 to child process and PID of child to parent process."; + +static PyObject * +posix_fork(self, args) + PyObject *self; + PyObject *args; +{ + int pid; + if (!PyArg_NoArgs(args)) + return NULL; + pid = fork(); + if (pid == -1) + return posix_error(); + PyOS_AfterFork(); + return PyInt_FromLong((long)pid); +} +#endif + + +#ifdef HAVE_GETEGID +static char posix_getegid__doc__[] = +"getegid() -> egid\n\ +Return the current process's effective group id."; + +static PyObject * +posix_getegid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)getegid()); +} +#endif + + +#ifdef HAVE_GETEUID +static char posix_geteuid__doc__[] = +"geteuid() -> euid\n\ +Return the current process's effective user id."; + +static PyObject * +posix_geteuid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)geteuid()); +} +#endif + + +#ifdef HAVE_GETGID +static char posix_getgid__doc__[] = +"getgid() -> gid\n\ +Return the current process's group id."; + +static PyObject * +posix_getgid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)getgid()); +} +#endif + + +static char posix_getpid__doc__[] = +"getpid() -> pid\n\ +Return the current process id"; + +static PyObject * +posix_getpid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)getpid()); +} + + +#ifdef HAVE_GETPGRP +static char posix_getpgrp__doc__[] = +"getpgrp() -> pgrp\n\ +Return the current process group id."; + +static PyObject * +posix_getpgrp(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; +#ifdef GETPGRP_HAVE_ARG + return PyInt_FromLong((long)getpgrp(0)); +#else /* GETPGRP_HAVE_ARG */ + return PyInt_FromLong((long)getpgrp()); +#endif /* GETPGRP_HAVE_ARG */ +} +#endif /* HAVE_GETPGRP */ + + +#ifdef HAVE_SETPGRP +static char posix_setpgrp__doc__[] = +"setpgrp() -> None\n\ +Make this process a session leader."; + +static PyObject * +posix_setpgrp(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; +#ifdef SETPGRP_HAVE_ARG + if (setpgrp(0, 0) < 0) +#else /* SETPGRP_HAVE_ARG */ + if (setpgrp() < 0) +#endif /* SETPGRP_HAVE_ARG */ + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + +#endif /* HAVE_SETPGRP */ + +#ifdef HAVE_GETPPID +static char posix_getppid__doc__[] = +"getppid() -> ppid\n\ +Return the parent's process id."; + +static PyObject * +posix_getppid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)getppid()); +} +#endif + + +#ifdef HAVE_GETUID +static char posix_getuid__doc__[] = +"getuid() -> uid\n\ +Return the current process's user id."; + +static PyObject * +posix_getuid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + return PyInt_FromLong((long)getuid()); +} +#endif + + +#ifdef HAVE_KILL +static char posix_kill__doc__[] = +"kill(pid, sig) -> None\n\ +Kill a process with a signal."; + +static PyObject * +posix_kill(self, args) + PyObject *self; + PyObject *args; +{ + int pid, sig; + if (!PyArg_Parse(args, "(ii)", &pid, &sig)) + return NULL; +#if defined(PYOS_OS2) + if (sig == XCPT_SIGNAL_INTR || sig == XCPT_SIGNAL_BREAK) { + APIRET rc; + if ((rc = DosSendSignalException(pid, sig)) != NO_ERROR) + return os2_error(rc); + + } else if (sig == XCPT_SIGNAL_KILLPROC) { + APIRET rc; + if ((rc = DosKillProcess(DKP_PROCESS, pid)) != NO_ERROR) + return os2_error(rc); + + } else + return NULL; /* Unrecognized Signal Requested */ +#else + if (kill(pid, sig) == -1) + return posix_error(); +#endif + Py_INCREF(Py_None); + return Py_None; +} +#endif + +#ifdef HAVE_PLOCK + +#ifdef HAVE_SYS_LOCK_H +#include +#endif + +static char posix_plock__doc__[] = +"plock(op) -> None\n\ +Lock program segments into memory."; + +static PyObject * +posix_plock(self, args) + PyObject *self; + PyObject *args; +{ + int op; + if (!PyArg_Parse(args, "i", &op)) + return NULL; + if (plock(op) == -1) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif + + +#ifdef HAVE_POPEN +static char posix_popen__doc__[] = +"popen(command [, mode='r' [, bufsize]]) -> pipe\n\ +Open a pipe to/from a command returning a file object."; + +#if defined(PYOS_OS2) +static int +async_system(const char *command) +{ + char *p, errormsg[256], args[1024]; + RESULTCODES rcodes; + APIRET rc; + char *shell = getenv("COMSPEC"); + if (!shell) + shell = "cmd"; + + strcpy(args, shell); + p = &args[ strlen(args)+1 ]; + strcpy(p, "/c "); + strcat(p, command); + p += strlen(p) + 1; + *p = '\0'; + + rc = DosExecPgm(errormsg, sizeof(errormsg), + EXEC_ASYNC, /* Execute Async w/o Wait for Results */ + args, + NULL, /* Inherit Parent's Environment */ + &rcodes, shell); + return rc; +} + +static FILE * +popen(const char *command, const char *mode, int pipesize, int *err) +{ + HFILE rhan, whan; + FILE *retfd = NULL; + APIRET rc = DosCreatePipe(&rhan, &whan, pipesize); + + if (rc != NO_ERROR) { + *err = rc; + return NULL; /* ERROR - Unable to Create Anon Pipe */ + } + + if (strchr(mode, 'r') != NULL) { /* Treat Command as a Data Source */ + int oldfd = dup(1); /* Save STDOUT Handle in Another Handle */ + + DosEnterCritSec(); /* Stop Other Threads While Changing Handles */ + close(1); /* Make STDOUT Available for Reallocation */ + + if (dup2(whan, 1) == 0) { /* Connect STDOUT to Pipe Write Side */ + DosClose(whan); /* Close Now-Unused Pipe Write Handle */ + + if (async_system(command) == NO_ERROR) + retfd = fdopen(rhan, mode); /* And Return Pipe Read Handle */ + } + + dup2(oldfd, 1); /* Reconnect STDOUT to Original Handle */ + DosExitCritSec(); /* Now Allow Other Threads to Run */ + + close(oldfd); /* And Close Saved STDOUT Handle */ + return retfd; /* Return fd of Pipe or NULL if Error */ + + } else if (strchr(mode, 'w')) { /* Treat Command as a Data Sink */ + int oldfd = dup(0); /* Save STDIN Handle in Another Handle */ + + DosEnterCritSec(); /* Stop Other Threads While Changing Handles */ + close(0); /* Make STDIN Available for Reallocation */ + + if (dup2(rhan, 0) == 0) { /* Connect STDIN to Pipe Read Side */ + DosClose(rhan); /* Close Now-Unused Pipe Read Handle */ + + if (async_system(command) == NO_ERROR) + retfd = fdopen(whan, mode); /* And Return Pipe Write Handle */ + } + + dup2(oldfd, 0); /* Reconnect STDIN to Original Handle */ + DosExitCritSec(); /* Now Allow Other Threads to Run */ + + close(oldfd); /* And Close Saved STDIN Handle */ + return retfd; /* Return fd of Pipe or NULL if Error */ + + } else { + *err = ERROR_INVALID_ACCESS; + return NULL; /* ERROR - Invalid Mode (Neither Read nor Write) */ + } +} + +static PyObject * +posix_popen(self, args) + PyObject *self; + PyObject *args; +{ + char *name; + char *mode = "r"; + int err, bufsize = -1; + FILE *fp; + PyObject *f; + if (!PyArg_ParseTuple(args, "s|si", &name, &mode, &bufsize)) + return NULL; + Py_BEGIN_ALLOW_THREADS + fp = popen(name, mode, (bufsize > 0) ? bufsize : 4096, &err); + Py_END_ALLOW_THREADS + if (fp == NULL) + return os2_error(err); + + f = PyFile_FromFile(fp, name, mode, fclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} + +#else +static PyObject * +posix_popen(self, args) + PyObject *self; + PyObject *args; +{ + char *name; + char *mode = "r"; + int bufsize = -1; + FILE *fp; + PyObject *f; + if (!PyArg_ParseTuple(args, "s|si", &name, &mode, &bufsize)) + return NULL; + Py_BEGIN_ALLOW_THREADS + fp = popen(name, mode); + Py_END_ALLOW_THREADS + if (fp == NULL) + return posix_error(); + f = PyFile_FromFile(fp, name, mode, pclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} +#endif + +#endif /* HAVE_POPEN */ + + +#ifdef HAVE_SETUID +static char posix_setuid__doc__[] = +"setuid(uid) -> None\n\ +Set the current process's user id."; +static PyObject * +posix_setuid(self, args) + PyObject *self; + PyObject *args; +{ + int uid; + if (!PyArg_Parse(args, "i", &uid)) + return NULL; + if (setuid(uid) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETUID */ + + +#ifdef HAVE_SETGID +static char posix_setgid__doc__[] = +"setgid(gid) -> None\n\ +Set the current process's group id."; + +static PyObject * +posix_setgid(self, args) + PyObject *self; + PyObject *args; +{ + int gid; + if (!PyArg_Parse(args, "i", &gid)) + return NULL; + if (setgid(gid) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETGID */ + + +#ifdef HAVE_WAITPID +static char posix_waitpid__doc__[] = +"waitpid(pid, options) -> (pid, status)\n\ +Wait for completion of a give child process."; + +static PyObject * +posix_waitpid(self, args) + PyObject *self; + PyObject *args; +{ + int pid, options; +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "(ii)", &pid, &options)) + return NULL; + Py_BEGIN_ALLOW_THREADS +#ifdef NeXT + pid = wait4(pid, &status, options, NULL); +#else + pid = waitpid(pid, &status, options); +#endif + Py_END_ALLOW_THREADS + if (pid == -1) + return posix_error(); + else + return Py_BuildValue("ii", pid, status_i); +} +#endif /* HAVE_WAITPID */ + + +#ifdef HAVE_WAIT +static char posix_wait__doc__[] = +"wait() -> (pid, status)\n\ +Wait for completion of a child process."; + +static PyObject * +posix_wait(self, args) + PyObject *self; + PyObject *args; +{ + int pid, sts; +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + Py_BEGIN_ALLOW_THREADS + pid = wait(&status); + Py_END_ALLOW_THREADS + if (pid == -1) + return posix_error(); + else + return Py_BuildValue("ii", pid, status_i); +} +#endif + + +static char posix_lstat__doc__[] = +"lstat(path) -> (mode,ino,dev,nlink,uid,gid,size,atime,mtime,ctime)\n\ +Like stat(path), but do not follow symbolic links."; + +static PyObject * +posix_lstat(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef HAVE_LSTAT + return posix_do_stat(self, args, lstat); +#else /* !HAVE_LSTAT */ + return posix_do_stat(self, args, stat); +#endif /* !HAVE_LSTAT */ +} + + +#ifdef HAVE_READLINK +static char posix_readlink__doc__[] = +"readlink(path) -> path\n\ +Return a string representing the path to which the symbolic link points."; + +static PyObject * +posix_readlink(self, args) + PyObject *self; + PyObject *args; +{ + char buf[MAXPATHLEN]; + char *path; + int n; + if (!PyArg_Parse(args, "s", &path)) + return NULL; + Py_BEGIN_ALLOW_THREADS + n = readlink(path, buf, (int) sizeof buf); + Py_END_ALLOW_THREADS + if (n < 0) + return posix_error_with_filename(path); + return PyString_FromStringAndSize(buf, n); +} +#endif /* HAVE_READLINK */ + + +#ifdef HAVE_SYMLINK +static char posix_symlink__doc__[] = +"symlink(src, dst) -> None\n\ +Create a symbolic link."; + +static PyObject * +posix_symlink(self, args) + PyObject *self; + PyObject *args; +{ + return posix_2str(args, symlink); +} +#endif /* HAVE_SYMLINK */ + + +#ifdef HAVE_TIMES +#ifndef HZ +#define HZ 60 /* Universal constant :-) */ +#endif /* HZ */ + +#if defined(PYCC_VACPP) && defined(PYOS_OS2) +static long +system_uptime() +{ + ULONG value = 0; + + Py_BEGIN_ALLOW_THREADS + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &value, sizeof(value)); + Py_END_ALLOW_THREADS + + return value; +} + +static PyObject * +posix_times(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + + /* Currently Only Uptime is Provided -- Others Later */ + return Py_BuildValue("ddddd", + (double)0 /* t.tms_utime / HZ */, + (double)0 /* t.tms_stime / HZ */, + (double)0 /* t.tms_cutime / HZ */, + (double)0 /* t.tms_cstime / HZ */, + (double)system_uptime() / 1000); +} +#else /* not OS2 */ +static PyObject * +posix_times(self, args) + PyObject *self; + PyObject *args; +{ + struct tms t; + clock_t c; + if (!PyArg_NoArgs(args)) + return NULL; + errno = 0; + c = times(&t); + if (c == (clock_t) -1) + return posix_error(); + return Py_BuildValue("ddddd", + (double)t.tms_utime / HZ, + (double)t.tms_stime / HZ, + (double)t.tms_cutime / HZ, + (double)t.tms_cstime / HZ, + (double)c / HZ); +} +#endif /* not OS2 */ +#endif /* HAVE_TIMES */ + + +#ifdef MS_WIN32 +#define HAVE_TIMES /* so the method table will pick it up */ +static PyObject * +posix_times(self, args) + PyObject *self; + PyObject *args; +{ + FILETIME create, exit, kernel, user; + HANDLE hProc; + if (!PyArg_NoArgs(args)) + return NULL; + hProc = GetCurrentProcess(); + GetProcessTimes(hProc, &create, &exit, &kernel, &user); + /* The fields of a FILETIME structure are the hi and lo part + of a 64-bit value expressed in 100 nanosecond units. + 1e7 is one second in such units; 1e-7 the inverse. + 429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7. + */ + return Py_BuildValue( + "ddddd", + (double)(kernel.dwHighDateTime*429.4967296 + + kernel.dwLowDateTime*1e-7), + (double)(user.dwHighDateTime*429.4967296 + + user.dwLowDateTime*1e-7), + (double)0, + (double)0, + (double)0); +} +#endif /* MS_WIN32 */ + +#ifdef HAVE_TIMES +static char posix_times__doc__[] = +"times() -> (utime, stime, cutime, cstime, elapsed_time)\n\ +Return a tuple of floating point numbers indicating process times."; +#endif + + +#ifdef HAVE_SETSID +static char posix_setsid__doc__[] = +"setsid() -> None\n\ +Call the system call setsid()."; + +static PyObject * +posix_setsid(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_NoArgs(args)) + return NULL; + if (setsid() < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETSID */ + +#ifdef HAVE_SETPGID +static char posix_setpgid__doc__[] = +"setpgid(pid, pgrp) -> None\n\ +Call the system call setpgid()."; + +static PyObject * +posix_setpgid(self, args) + PyObject *self; + PyObject *args; +{ + int pid, pgrp; + if (!PyArg_Parse(args, "(ii)", &pid, &pgrp)) + return NULL; + if (setpgid(pid, pgrp) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETPGID */ + + +#ifdef HAVE_TCGETPGRP +static char posix_tcgetpgrp__doc__[] = +"tcgetpgrp(fd) -> pgid\n\ +Return the process group associated with the terminal given by a fd."; + +static PyObject * +posix_tcgetpgrp(self, args) + PyObject *self; + PyObject *args; +{ + int fd, pgid; + if (!PyArg_Parse(args, "i", &fd)) + return NULL; + pgid = tcgetpgrp(fd); + if (pgid < 0) + return posix_error(); + return PyInt_FromLong((long)pgid); +} +#endif /* HAVE_TCGETPGRP */ + + +#ifdef HAVE_TCSETPGRP +static char posix_tcsetpgrp__doc__[] = +"tcsetpgrp(fd, pgid) -> None\n\ +Set the process group associated with the terminal given by a fd."; + +static PyObject * +posix_tcsetpgrp(self, args) + PyObject *self; + PyObject *args; +{ + int fd, pgid; + if (!PyArg_Parse(args, "(ii)", &fd, &pgid)) + return NULL; + if (tcsetpgrp(fd, pgid) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_TCSETPGRP */ + +/* Functions acting on file descriptors */ + +static char posix_open__doc__[] = +"open(filename, flag [, mode=0777]) -> fd\n\ +Open a file (for low level IO)."; + +static PyObject * +posix_open(self, args) + PyObject *self; + PyObject *args; +{ + char *file; + int flag; + int mode = 0777; + int fd; + if (!PyArg_ParseTuple(args, "si|i", &file, &flag, &mode)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + fd = open(file, flag, mode); + Py_END_ALLOW_THREADS + if (fd < 0) + return posix_error_with_filename(file); + return PyInt_FromLong((long)fd); +} + + +static char posix_close__doc__[] = +"close(fd) -> None\n\ +Close a file descriptor (for low level IO)."; + +static PyObject * +posix_close(self, args) + PyObject *self; + PyObject *args; +{ + int fd, res; + if (!PyArg_Parse(args, "i", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = close(fd); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + + +static char posix_dup__doc__[] = +"dup(fd) -> fd2\n\ +Return a duplicate of a file descriptor."; + +static PyObject * +posix_dup(self, args) + PyObject *self; + PyObject *args; +{ + int fd; + if (!PyArg_Parse(args, "i", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + fd = dup(fd); + Py_END_ALLOW_THREADS + if (fd < 0) + return posix_error(); + return PyInt_FromLong((long)fd); +} + + +static char posix_dup2__doc__[] = +"dup2(fd, fd2) -> None\n\ +Duplicate file descriptor."; + +static PyObject * +posix_dup2(self, args) + PyObject *self; + PyObject *args; +{ + int fd, fd2, res; + if (!PyArg_Parse(args, "(ii)", &fd, &fd2)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = dup2(fd, fd2); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + + +static char posix_lseek__doc__[] = +"lseek(fd, pos, how) -> newpos\n\ +Set the current position of a file descriptor."; + +static PyObject * +posix_lseek(self, args) + PyObject *self; + PyObject *args; +{ + int fd, how; + off_t pos, res; + PyObject *posobj; + if (!PyArg_Parse(args, "(iOi)", &fd, &posobj, &how)) + return NULL; +#ifdef SEEK_SET + /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */ + switch (how) { + case 0: how = SEEK_SET; break; + case 1: how = SEEK_CUR; break; + case 2: how = SEEK_END; break; + } +#endif /* SEEK_END */ + +#if !defined(HAVE_LARGEFILE_SUPPORT) + pos = PyInt_AsLong(posobj); +#else + pos = PyLong_Check(posobj) ? + PyLong_AsLongLong(posobj) : PyInt_AsLong(posobj); +#endif + if (PyErr_Occurred()) + return NULL; + + Py_BEGIN_ALLOW_THREADS + res = lseek(fd, pos, how); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + +#if !defined(HAVE_LARGEFILE_SUPPORT) + return PyInt_FromLong(res); +#else + return PyLong_FromLongLong(res); +#endif +} + + +static char posix_read__doc__[] = +"read(fd, buffersize) -> string\n\ +Read a file descriptor."; + +static PyObject * +posix_read(self, args) + PyObject *self; + PyObject *args; +{ + int fd, size, n; + PyObject *buffer; + if (!PyArg_Parse(args, "(ii)", &fd, &size)) + return NULL; + buffer = PyString_FromStringAndSize((char *)NULL, size); + if (buffer == NULL) + return NULL; + Py_BEGIN_ALLOW_THREADS + n = read(fd, PyString_AsString(buffer), size); + Py_END_ALLOW_THREADS + if (n < 0) { + Py_DECREF(buffer); + return posix_error(); + } + if (n != size) + _PyString_Resize(&buffer, n); + return buffer; +} + + +static char posix_write__doc__[] = +"write(fd, string) -> byteswritten\n\ +Write a string to a file descriptor."; + +static PyObject * +posix_write(self, args) + PyObject *self; + PyObject *args; +{ + int fd, size; + char *buffer; + if (!PyArg_Parse(args, "(is#)", &fd, &buffer, &size)) + return NULL; + Py_BEGIN_ALLOW_THREADS + size = write(fd, buffer, size); + Py_END_ALLOW_THREADS + if (size < 0) + return posix_error(); + return PyInt_FromLong((long)size); +} + + +static char posix_fstat__doc__[]= +"fstat(fd) -> (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\ +Like stat(), but for an open file descriptor."; + +static PyObject * +posix_fstat(self, args) + PyObject *self; + PyObject *args; +{ + int fd; + struct stat st; + int res; + if (!PyArg_Parse(args, "i", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = fstat(fd, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error(); +#if !defined(HAVE_LARGEFILE_SUPPORT) + return Py_BuildValue("(llllllllll)", + (long)st.st_mode, + (long)st.st_ino, + (long)st.st_dev, + (long)st.st_nlink, + (long)st.st_uid, + (long)st.st_gid, + (long)st.st_size, + (long)st.st_atime, + (long)st.st_mtime, + (long)st.st_ctime); +#else + return Py_BuildValue("(lLllllLlll)", + (long)st.st_mode, + (LONG_LONG)st.st_ino, + (long)st.st_dev, + (long)st.st_nlink, + (long)st.st_uid, + (long)st.st_gid, + (LONG_LONG)st.st_size, + (long)st.st_atime, + (long)st.st_mtime, + (long)st.st_ctime); +#endif +} + + +static char posix_fdopen__doc__[] = +"fdopen(fd, [, mode='r' [, bufsize]]) -> file_object\n\ +Return an open file object connected to a file descriptor."; + +static PyObject * +posix_fdopen(self, args) + PyObject *self; + PyObject *args; +{ + extern int fclose Py_PROTO((FILE *)); + int fd; + char *mode = "r"; + int bufsize = -1; + FILE *fp; + PyObject *f; + if (!PyArg_ParseTuple(args, "i|si", &fd, &mode, &bufsize)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + fp = fdopen(fd, mode); + Py_END_ALLOW_THREADS + if (fp == NULL) + return posix_error(); + f = PyFile_FromFile(fp, "(fdopen)", mode, fclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} + + +#ifdef HAVE_PIPE +static char posix_pipe__doc__[] = +"pipe() -> (read_end, write_end)\n\ +Create a pipe."; + +static PyObject * +posix_pipe(self, args) + PyObject *self; + PyObject *args; +{ +#if defined(PYOS_OS2) + HFILE read, write; + APIRET rc; + + if (!PyArg_Parse(args, "")) + return NULL; + + Py_BEGIN_ALLOW_THREADS + rc = DosCreatePipe( &read, &write, 4096); + Py_END_ALLOW_THREADS + if (rc != NO_ERROR) + return os2_error(rc); + + return Py_BuildValue("(ii)", read, write); +#else +#if !defined(MS_WIN32) + int fds[2]; + int res; + if (!PyArg_Parse(args, "")) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = pipe(fds); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error(); + return Py_BuildValue("(ii)", fds[0], fds[1]); +#else /* MS_WIN32 */ + HANDLE read, write; + int read_fd, write_fd; + BOOL ok; + if (!PyArg_Parse(args, "")) + return NULL; + Py_BEGIN_ALLOW_THREADS + ok = CreatePipe(&read, &write, NULL, 0); + Py_END_ALLOW_THREADS + if (!ok) + return posix_error(); + read_fd = _open_osfhandle((long)read, 0); + write_fd = _open_osfhandle((long)write, 1); + return Py_BuildValue("(ii)", read_fd, write_fd); +#endif /* MS_WIN32 */ +#endif +} +#endif /* HAVE_PIPE */ + + +#ifdef HAVE_MKFIFO +static char posix_mkfifo__doc__[] = +"mkfifo(file, [, mode=0666]) -> None\n\ +Create a FIFO (a POSIX named pipe)."; + +static PyObject * +posix_mkfifo(self, args) + PyObject *self; + PyObject *args; +{ + char *file; + int mode = 0666; + int res; + if (!PyArg_ParseTuple(args, "s|i", &file, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = mkfifo(file, mode); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif + + +#ifdef HAVE_FTRUNCATE +static char posix_ftruncate__doc__[] = +"ftruncate(fd, length) -> None\n\ +Truncate a file to a specified length."; + +static PyObject * +posix_ftruncate(self, args) + PyObject *self; /* Not used */ + PyObject *args; +{ + int fd; + off_t length; + int res; + PyObject *lenobj; + + if (!PyArg_Parse(args, "(iO)", &fd, &lenobj)) + return NULL; + +#if !defined(HAVE_LARGEFILE_SUPPORT) + length = PyInt_AsLong(lenobj); +#else + length = PyLong_Check(lenobj) ? + PyLong_AsLongLong(lenobj) : PyInt_AsLong(lenobj); +#endif + if (PyErr_Occurred()) + return NULL; + + Py_BEGIN_ALLOW_THREADS + res = ftruncate(fd, length); + Py_END_ALLOW_THREADS + if (res < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} +#endif + +#ifdef NeXT +#define HAVE_PUTENV +/* Steve Spicklemire got this putenv from NeXTAnswers */ +static int +putenv(char *newval) +{ + extern char **environ; + + static int firstTime = 1; + char **ep; + char *cp; + int esiz; + char *np; + + if (!(np = strchr(newval, '='))) + return 1; + *np = '\0'; + + /* look it up */ + for (ep=environ ; *ep ; ep++) + { + /* this should always be true... */ + if (cp = strchr(*ep, '=')) + { + *cp = '\0'; + if (!strcmp(*ep, newval)) + { + /* got it! */ + *cp = '='; + break; + } + *cp = '='; + } + else + { + *np = '='; + return 1; + } + } + + *np = '='; + if (*ep) + { + /* the string was already there: + just replace it with the new one */ + *ep = newval; + return 0; + } + + /* expand environ by one */ + for (esiz=2, ep=environ ; *ep ; ep++) + esiz++; + if (firstTime) + { + char **epp; + char **newenv; + if (!(newenv = malloc(esiz * sizeof(char *)))) + return 1; + + for (ep=environ, epp=newenv ; *ep ;) + *epp++ = *ep++; + *epp++ = newval; + *epp = (char *) 0; + environ = newenv; + } + else + { + if (!(environ = realloc(environ, esiz * sizeof(char *)))) + return 1; + environ[esiz - 2] = newval; + environ[esiz - 1] = (char *) 0; + firstTime = 0; + } + + return 0; +} +#endif /* NeXT */ + + +#ifdef HAVE_PUTENV +static char posix_putenv__doc__[] = +"putenv(key, value) -> None\n\ +Change or add an environment variable."; + +#ifdef __BEOS__ +/* We have putenv(), but not in the headers (as of PR2). - [cjh] */ +int putenv( const char *str ); +#endif + +static PyObject * +posix_putenv(self, args) + PyObject *self; + PyObject *args; +{ + char *s1, *s2; + char *new; + + if (!PyArg_ParseTuple(args, "ss", &s1, &s2)) + return NULL; + +#if defined(PYOS_OS2) + if (stricmp(s1, "BEGINLIBPATH") == 0) { + APIRET rc; + + if (strlen(s2) == 0) /* If New Value is an Empty String */ + s2 = NULL; /* Then OS/2 API Wants a NULL to Undefine It */ + + rc = DosSetExtLIBPATH(s2, BEGIN_LIBPATH); + if (rc != NO_ERROR) + return os2_error(rc); + + } else if (stricmp(s1, "ENDLIBPATH") == 0) { + APIRET rc; + + if (strlen(s2) == 0) /* If New Value is an Empty String */ + s2 = NULL; /* Then OS/2 API Wants a NULL to Undefine It */ + + rc = DosSetExtLIBPATH(s2, END_LIBPATH); + if (rc != NO_ERROR) + return os2_error(rc); + } else { +#endif + + /* XXX This leaks memory -- not easy to fix :-( */ + if ((new = malloc(strlen(s1) + strlen(s2) + 2)) == NULL) + return PyErr_NoMemory(); + (void) sprintf(new, "%s=%s", s1, s2); + if (putenv(new)) { + posix_error(); + return NULL; + } + +#if defined(PYOS_OS2) + } +#endif + Py_INCREF(Py_None); + return Py_None; +} +#endif /* putenv */ + +#ifdef HAVE_STRERROR +static char posix_strerror__doc__[] = +"strerror(code) -> string\n\ +Translate an error code to a message string."; + +PyObject * +posix_strerror(self, args) + PyObject *self; + PyObject *args; +{ + int code; + char *message; + if (!PyArg_ParseTuple(args, "i", &code)) + return NULL; + message = strerror(code); + if (message == NULL) { + PyErr_SetString(PyExc_ValueError, + "strerror code out of range"); + return NULL; + } + return PyString_FromString(message); +} +#endif /* strerror */ + + +#ifdef HAVE_SYS_WAIT_H + +#ifdef WIFSTOPPED +static char posix_WIFSTOPPED__doc__[] = +"WIFSTOPPED(status) -> Boolean\n\ +Return true if the process returning 'status' was stopped."; + +static PyObject * +posix_WIFSTOPPED(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WIFSTOPPED(status)); +} +#endif /* WIFSTOPPED */ + +#ifdef WIFSIGNALED +static char posix_WIFSIGNALED__doc__[] = +"WIFSIGNALED(status) -> Boolean\n\ +Return true if the process returning 'status' was terminated by a signal."; + +static PyObject * +posix_WIFSIGNALED(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WIFSIGNALED(status)); +} +#endif /* WIFSIGNALED */ + +#ifdef WIFEXITED +static char posix_WIFEXITED__doc__[] = +"WIFEXITED(status) -> Boolean\n\ +Return true if the process returning 'status' exited using the exit()\n\ +system call."; + +static PyObject * +posix_WIFEXITED(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WIFEXITED(status)); +} +#endif /* WIFEXITED */ + +#ifdef WEXITSTATUS +static char posix_WEXITSTATUS__doc__[] = +"WEXITSTATUS(status) -> integer\n\ +Return the process return code from 'status'."; + +static PyObject * +posix_WEXITSTATUS(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WEXITSTATUS(status)); +} +#endif /* WEXITSTATUS */ + +#ifdef WTERMSIG +static char posix_WTERMSIG__doc__[] = +"WTERMSIG(status) -> integer\n\ +Return the signal that terminated the process that provided the 'status'\n\ +value."; + +static PyObject * +posix_WTERMSIG(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WTERMSIG(status)); +} +#endif /* WTERMSIG */ + +#ifdef WSTOPSIG +static char posix_WSTOPSIG__doc__[] = +"WSTOPSIG(status) -> integer\n\ +Return the signal that stopped the process that provided the 'status' value."; + +static PyObject * +posix_WSTOPSIG(self, args) + PyObject *self; + PyObject *args; +{ +#ifdef UNION_WAIT + union wait status; +#define status_i (status.w_status) +#else + int status; +#define status_i status +#endif + status_i = 0; + + if (!PyArg_Parse(args, "i", &status_i)) + { + return NULL; + } + + return Py_BuildValue("i", WSTOPSIG(status)); +} +#endif /* WSTOPSIG */ + +#endif /* HAVE_SYS_WAIT_H */ + + +#if defined(HAVE_FSTATVFS) +#include + +static char posix_fstatvfs__doc__[] = +"fstatvfs(fd) -> \n\ + (bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flag, namemax)\n\ +Perform an fstatvfs system call on the given fd."; + +static PyObject * +posix_fstatvfs(self, args) + PyObject *self; + PyObject *args; +{ + int fd, res; + struct statvfs st; + if (!PyArg_ParseTuple(args, "i", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = fstatvfs(fd, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error(); +#if !defined(HAVE_LARGEFILE_SUPPORT) + return Py_BuildValue("(llllllllll)", + (long) st.f_bsize, + (long) st.f_frsize, + (long) st.f_blocks, + (long) st.f_bfree, + (long) st.f_bavail, + (long) st.f_files, + (long) st.f_ffree, + (long) st.f_favail, + (long) st.f_flag, + (long) st.f_namemax); +#else + return Py_BuildValue("(llLLLLLLll)", + (long) st.f_bsize, + (long) st.f_frsize, + (LONG_LONG) st.f_blocks, + (LONG_LONG) st.f_bfree, + (LONG_LONG) st.f_bavail, + (LONG_LONG) st.f_files, + (LONG_LONG) st.f_ffree, + (LONG_LONG) st.f_favail, + (long) st.f_flag, + (long) st.f_namemax); +#endif +} +#endif /* HAVE_FSTATVFS */ + + +#if defined(HAVE_STATVFS) +#include + +static char posix_statvfs__doc__[] = +"statvfs(path) -> \n\ + (bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flag, namemax)\n\ +Perform a statvfs system call on the given path."; + +static PyObject * +posix_statvfs(self, args) + PyObject *self; + PyObject *args; +{ + char *path; + int res; + struct statvfs st; + if (!PyArg_ParseTuple(args, "s", &path)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = statvfs(path, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error_with_filename(path); +#if !defined(HAVE_LARGEFILE_SUPPORT) + return Py_BuildValue("(llllllllll)", + (long) st.f_bsize, + (long) st.f_frsize, + (long) st.f_blocks, + (long) st.f_bfree, + (long) st.f_bavail, + (long) st.f_files, + (long) st.f_ffree, + (long) st.f_favail, + (long) st.f_flag, + (long) st.f_namemax); +#else /* HAVE_LARGEFILE_SUPPORT */ + return Py_BuildValue("(llLLLLLLll)", + (long) st.f_bsize, + (long) st.f_frsize, + (LONG_LONG) st.f_blocks, + (LONG_LONG) st.f_bfree, + (LONG_LONG) st.f_bavail, + (LONG_LONG) st.f_files, + (LONG_LONG) st.f_ffree, + (LONG_LONG) st.f_favail, + (long) st.f_flag, + (long) st.f_namemax); +#endif +} +#endif /* HAVE_STATVFS */ + + +static PyMethodDef posix_methods[] = { + {"access", posix_access, 0, posix_access__doc__}, +#ifdef HAVE_TTYNAME + {"ttyname", posix_ttyname, 0, posix_ttyname__doc__}, +#endif + {"chdir", posix_chdir, 0, posix_chdir__doc__}, + {"chmod", posix_chmod, 0, posix_chmod__doc__}, +#ifdef HAVE_CHOWN + {"chown", posix_chown, 0, posix_chown__doc__}, +#endif /* HAVE_CHOWN */ +#ifdef HAVE_GETCWD + {"getcwd", posix_getcwd, 0, posix_getcwd__doc__}, +#endif +#ifdef HAVE_LINK + {"link", posix_link, 0, posix_link__doc__}, +#endif /* HAVE_LINK */ + {"listdir", posix_listdir, 0, posix_listdir__doc__}, + {"lstat", posix_lstat, 0, posix_lstat__doc__}, + {"mkdir", posix_mkdir, 1, posix_mkdir__doc__}, +#ifdef HAVE_NICE + {"nice", posix_nice, 0, posix_nice__doc__}, +#endif /* HAVE_NICE */ +#ifdef HAVE_READLINK + {"readlink", posix_readlink, 0, posix_readlink__doc__}, +#endif /* HAVE_READLINK */ + {"rename", posix_rename, 0, posix_rename__doc__}, + {"rmdir", posix_rmdir, 0, posix_rmdir__doc__}, + {"stat", posix_stat, 0, posix_stat__doc__}, +#ifdef HAVE_SYMLINK + {"symlink", posix_symlink, 0, posix_symlink__doc__}, +#endif /* HAVE_SYMLINK */ +#ifdef HAVE_SYSTEM + {"system", posix_system, 0, posix_system__doc__}, +#endif + {"umask", posix_umask, 0, posix_umask__doc__}, +#ifdef HAVE_UNAME + {"uname", posix_uname, 0, posix_uname__doc__}, +#endif /* HAVE_UNAME */ + {"unlink", posix_unlink, 0, posix_unlink__doc__}, + {"remove", posix_unlink, 0, posix_remove__doc__}, + {"utime", posix_utime, 0, posix_utime__doc__}, +#ifdef HAVE_TIMES + {"times", posix_times, 0, posix_times__doc__}, +#endif /* HAVE_TIMES */ + {"_exit", posix__exit, 0, posix__exit__doc__}, +#ifdef HAVE_EXECV + {"execv", posix_execv, 0, posix_execv__doc__}, + {"execve", posix_execve, 0, posix_execve__doc__}, +#endif /* HAVE_EXECV */ +#ifdef HAVE_SPAWNV + {"spawnv", posix_spawnv, 0, posix_spawnv__doc__}, + {"spawnve", posix_spawnve, 0, posix_spawnve__doc__}, +#endif /* HAVE_SPAWNV */ +#ifdef HAVE_FORK + {"fork", posix_fork, 0, posix_fork__doc__}, +#endif /* HAVE_FORK */ +#ifdef HAVE_GETEGID + {"getegid", posix_getegid, 0, posix_getegid__doc__}, +#endif /* HAVE_GETEGID */ +#ifdef HAVE_GETEUID + {"geteuid", posix_geteuid, 0, posix_geteuid__doc__}, +#endif /* HAVE_GETEUID */ +#ifdef HAVE_GETGID + {"getgid", posix_getgid, 0, posix_getgid__doc__}, +#endif /* HAVE_GETGID */ + {"getpid", posix_getpid, 0, posix_getpid__doc__}, +#ifdef HAVE_GETPGRP + {"getpgrp", posix_getpgrp, 0, posix_getpgrp__doc__}, +#endif /* HAVE_GETPGRP */ +#ifdef HAVE_GETPPID + {"getppid", posix_getppid, 0, posix_getppid__doc__}, +#endif /* HAVE_GETPPID */ +#ifdef HAVE_GETUID + {"getuid", posix_getuid, 0, posix_getuid__doc__}, +#endif /* HAVE_GETUID */ +#ifdef HAVE_KILL + {"kill", posix_kill, 0, posix_kill__doc__}, +#endif /* HAVE_KILL */ +#ifdef HAVE_PLOCK + {"plock", posix_plock, 0, posix_plock__doc__}, +#endif /* HAVE_PLOCK */ +#ifdef HAVE_POPEN + {"popen", posix_popen, 1, posix_popen__doc__}, +#endif /* HAVE_POPEN */ +#ifdef HAVE_SETUID + {"setuid", posix_setuid, 0, posix_setuid__doc__}, +#endif /* HAVE_SETUID */ +#ifdef HAVE_SETGID + {"setgid", posix_setgid, 0, posix_setgid__doc__}, +#endif /* HAVE_SETGID */ +#ifdef HAVE_SETPGRP + {"setpgrp", posix_setpgrp, 0, posix_setpgrp__doc__}, +#endif /* HAVE_SETPGRP */ +#ifdef HAVE_WAIT + {"wait", posix_wait, 0, posix_wait__doc__}, +#endif /* HAVE_WAIT */ +#ifdef HAVE_WAITPID + {"waitpid", posix_waitpid, 0, posix_waitpid__doc__}, +#endif /* HAVE_WAITPID */ +#ifdef HAVE_SETSID + {"setsid", posix_setsid, 0, posix_setsid__doc__}, +#endif /* HAVE_SETSID */ +#ifdef HAVE_SETPGID + {"setpgid", posix_setpgid, 0, posix_setpgid__doc__}, +#endif /* HAVE_SETPGID */ +#ifdef HAVE_TCGETPGRP + {"tcgetpgrp", posix_tcgetpgrp, 0, posix_tcgetpgrp__doc__}, +#endif /* HAVE_TCGETPGRP */ +#ifdef HAVE_TCSETPGRP + {"tcsetpgrp", posix_tcsetpgrp, 0, posix_tcsetpgrp__doc__}, +#endif /* HAVE_TCSETPGRP */ + {"open", posix_open, 1, posix_open__doc__}, + {"close", posix_close, 0, posix_close__doc__}, + {"dup", posix_dup, 0, posix_dup__doc__}, + {"dup2", posix_dup2, 0, posix_dup2__doc__}, + {"lseek", posix_lseek, 0, posix_lseek__doc__}, + {"read", posix_read, 0, posix_read__doc__}, + {"write", posix_write, 0, posix_write__doc__}, + {"fstat", posix_fstat, 0, posix_fstat__doc__}, + {"fdopen", posix_fdopen, 1, posix_fdopen__doc__}, +#ifdef HAVE_PIPE + {"pipe", posix_pipe, 0, posix_pipe__doc__}, +#endif +#ifdef HAVE_MKFIFO + {"mkfifo", posix_mkfifo, 1, posix_mkfifo__doc__}, +#endif +#ifdef HAVE_FTRUNCATE + {"ftruncate", posix_ftruncate, 1, posix_ftruncate__doc__}, +#endif +#ifdef HAVE_PUTENV + {"putenv", posix_putenv, 1, posix_putenv__doc__}, +#endif +#ifdef HAVE_STRERROR + {"strerror", posix_strerror, 1, posix_strerror__doc__}, +#endif +#ifdef HAVE_FSYNC + {"fsync", posix_fsync, 0, posix_fsync__doc__}, +#endif +#ifdef HAVE_FDATASYNC + {"fdatasync", posix_fdatasync, 0, posix_fdatasync__doc__}, +#endif +#ifdef HAVE_SYS_WAIT_H +#ifdef WIFSTOPPED + {"WIFSTOPPED", posix_WIFSTOPPED, 0, posix_WIFSTOPPED__doc__}, +#endif /* WIFSTOPPED */ +#ifdef WIFSIGNALED + {"WIFSIGNALED", posix_WIFSIGNALED, 0, posix_WIFSIGNALED__doc__}, +#endif /* WIFSIGNALED */ +#ifdef WIFEXITED + {"WIFEXITED", posix_WIFEXITED, 0, posix_WIFEXITED__doc__}, +#endif /* WIFEXITED */ +#ifdef WEXITSTATUS + {"WEXITSTATUS", posix_WEXITSTATUS, 0, posix_WEXITSTATUS__doc__}, +#endif /* WEXITSTATUS */ +#ifdef WTERMSIG + {"WTERMSIG", posix_WTERMSIG, 0, posix_WTERMSIG__doc__}, +#endif /* WTERMSIG */ +#ifdef WSTOPSIG + {"WSTOPSIG", posix_WSTOPSIG, 0, posix_WSTOPSIG__doc__}, +#endif /* WSTOPSIG */ +#endif /* HAVE_SYS_WAIT_H */ +#ifdef HAVE_FSTATVFS + {"fstatvfs", posix_fstatvfs, 1, posix_fstatvfs__doc__}, +#endif +#ifdef HAVE_STATVFS + {"statvfs", posix_statvfs, 1, posix_statvfs__doc__}, +#endif + {NULL, NULL} /* Sentinel */ +}; + + +static int +ins(d, symbol, value) + PyObject* d; + char* symbol; + long value; +{ + PyObject* v = PyInt_FromLong(value); + if (!v || PyDict_SetItemString(d, symbol, v) < 0) + return -1; /* triggers fatal error */ + + Py_DECREF(v); + return 0; +} + +#if defined(PYOS_OS2) +/* Insert Platform-Specific Constant Values (Strings & Numbers) of Common Use */ +static int insertvalues(PyObject *d) +{ + APIRET rc; + ULONG values[QSV_MAX+1]; + PyObject *v; + char *ver, tmp[10]; + + Py_BEGIN_ALLOW_THREADS + rc = DosQuerySysInfo(1, QSV_MAX, &values[1], sizeof(values)); + Py_END_ALLOW_THREADS + + if (rc != NO_ERROR) { + os2_error(rc); + return -1; + } + + if (ins(d, "meminstalled", values[QSV_TOTPHYSMEM])) return -1; + if (ins(d, "memkernel", values[QSV_TOTRESMEM])) return -1; + if (ins(d, "memvirtual", values[QSV_TOTAVAILMEM])) return -1; + if (ins(d, "maxpathlen", values[QSV_MAX_PATH_LENGTH])) return -1; + if (ins(d, "maxnamelen", values[QSV_MAX_COMP_LENGTH])) return -1; + if (ins(d, "revision", values[QSV_VERSION_REVISION])) return -1; + if (ins(d, "timeslice", values[QSV_MIN_SLICE])) return -1; + + switch (values[QSV_VERSION_MINOR]) { + case 0: ver = "2.00"; break; + case 10: ver = "2.10"; break; + case 11: ver = "2.11"; break; + case 30: ver = "3.00"; break; + case 40: ver = "4.00"; break; + case 50: ver = "5.00"; break; + default: + sprintf(tmp, "%d-%d", values[QSV_VERSION_MAJOR], + values[QSV_VERSION_MINOR]); + ver = &tmp[0]; + } + + /* Add Indicator of the Version of the Operating System */ + v = PyString_FromString(ver); + if (!v || PyDict_SetItemString(d, "version", v) < 0) + return -1; + Py_DECREF(v); + + /* Add Indicator of Which Drive was Used to Boot the System */ + tmp[0] = 'A' + values[QSV_BOOT_DRIVE] - 1; + tmp[1] = ':'; + tmp[2] = '\0'; + + v = PyString_FromString(tmp); + if (!v || PyDict_SetItemString(d, "bootdrive", v) < 0) + return -1; + Py_DECREF(v); + + return 0; +} +#endif + +static int +all_ins(d) + PyObject* d; +{ +#ifdef F_OK + if (ins(d, "F_OK", (long)F_OK)) return -1; +#endif +#ifdef R_OK + if (ins(d, "R_OK", (long)R_OK)) return -1; +#endif +#ifdef W_OK + if (ins(d, "W_OK", (long)W_OK)) return -1; +#endif +#ifdef X_OK + if (ins(d, "X_OK", (long)X_OK)) return -1; +#endif +#ifdef WNOHANG + if (ins(d, "WNOHANG", (long)WNOHANG)) return -1; +#endif +#ifdef O_RDONLY + if (ins(d, "O_RDONLY", (long)O_RDONLY)) return -1; +#endif +#ifdef O_WRONLY + if (ins(d, "O_WRONLY", (long)O_WRONLY)) return -1; +#endif +#ifdef O_RDWR + if (ins(d, "O_RDWR", (long)O_RDWR)) return -1; +#endif +#ifdef O_NDELAY + if (ins(d, "O_NDELAY", (long)O_NDELAY)) return -1; +#endif +#ifdef O_NONBLOCK + if (ins(d, "O_NONBLOCK", (long)O_NONBLOCK)) return -1; +#endif +#ifdef O_APPEND + if (ins(d, "O_APPEND", (long)O_APPEND)) return -1; +#endif +#ifdef O_DSYNC + if (ins(d, "O_DSYNC", (long)O_DSYNC)) return -1; +#endif +#ifdef O_RSYNC + if (ins(d, "O_RSYNC", (long)O_RSYNC)) return -1; +#endif +#ifdef O_SYNC + if (ins(d, "O_SYNC", (long)O_SYNC)) return -1; +#endif +#ifdef O_NOCTTY + if (ins(d, "O_NOCTTY", (long)O_NOCTTY)) return -1; +#endif +#ifdef O_CREAT + if (ins(d, "O_CREAT", (long)O_CREAT)) return -1; +#endif +#ifdef O_EXCL + if (ins(d, "O_EXCL", (long)O_EXCL)) return -1; +#endif +#ifdef O_TRUNC + if (ins(d, "O_TRUNC", (long)O_TRUNC)) return -1; +#endif +#ifdef O_BINARY + if (ins(d, "O_BINARY", (long)O_BINARY)) return -1; +#endif +#ifdef O_TEXT + if (ins(d, "O_TEXT", (long)O_TEXT)) return -1; +#endif + +#ifdef HAVE_SPAWNV + if (ins(d, "P_WAIT", (long)_P_WAIT)) return -1; + if (ins(d, "P_NOWAIT", (long)_P_NOWAIT)) return -1; + if (ins(d, "P_OVERLAY", (long)_OLD_P_OVERLAY)) return -1; + if (ins(d, "P_NOWAITO", (long)_P_NOWAITO)) return -1; + if (ins(d, "P_DETACH", (long)_P_DETACH)) return -1; +#endif + +#if defined(PYOS_OS2) + if (insertvalues(d)) return -1; +#endif + return 0; +} + + +#if ( defined(_MSC_VER) || defined(__WATCOMC__) ) && !defined(__QNX__) +#define INITFUNC initnt +#define MODNAME "nt" +#else +#if defined(PYOS_OS2) +#define INITFUNC initos2 +#define MODNAME "os2" +#else +#define INITFUNC initposix +#define MODNAME "posix" +#endif +#endif + +DL_EXPORT(void) +INITFUNC() +{ + PyObject *m, *d, *v; + + m = Py_InitModule4(MODNAME, + posix_methods, + posix__doc__, + (PyObject *)NULL, + PYTHON_API_VERSION); + d = PyModule_GetDict(m); + + /* Initialize environ dictionary */ + v = convertenviron(); + if (v == NULL || PyDict_SetItemString(d, "environ", v) != 0) + return; + Py_DECREF(v); + + if (all_ins(d)) + return; + + PyDict_SetItemString(d, "error", PyExc_OSError); +} diff --git a/src/main/resource/testFiles/cpython/revFiles/df0d00_1254d7_Python#ceval.c b/src/main/resource/testFiles/cpython/revFiles/df0d00_1254d7_Python#ceval.c new file mode 100644 index 0000000..ead65b9 --- /dev/null +++ b/src/main/resource/testFiles/cpython/revFiles/df0d00_1254d7_Python#ceval.c @@ -0,0 +1,2740 @@ +/*********************************************************** +Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, +The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI or Corporation for National Research Initiatives or +CNRI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +While CWI is the initial source for this software, a modified version +is made available by the Corporation for National Research Initiatives +(CNRI) at the Internet address ftp://ftp.python.org. + +STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH +CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Execute compiled code */ + +/* XXX TO DO: + XXX how to pass arguments to call_trace? + XXX speed up searching for keywords by using a dictionary + XXX document it! + */ + +#include "Python.h" + +#include "compile.h" +#include "frameobject.h" +#include "eval.h" +#include "opcode.h" + +#include + +#ifdef HAVE_LIMITS_H +#include +#else +#define INT_MAX 2147483647 +#endif + +/* Turn this on if your compiler chokes on the big switch: */ +/* #define CASE_TOO_BIG 1 */ + +#ifdef Py_DEBUG +/* For debugging the interpreter: */ +#define LLTRACE 1 /* Low-level trace feature */ +#define CHECKEXC 1 /* Double-check exception checking */ +#endif + + +/* Forward declarations */ + +static PyObject *eval_code2 Py_PROTO((PyCodeObject *, + PyObject *, PyObject *, + PyObject **, int, + PyObject **, int, + PyObject **, int, + PyObject *)); +#ifdef LLTRACE +static int prtrace Py_PROTO((PyObject *, char *)); +#endif +static void call_exc_trace Py_PROTO((PyObject **, PyObject**, + PyFrameObject *)); +static int call_trace Py_PROTO((PyObject **, PyObject **, + PyFrameObject *, char *, PyObject *)); +static PyObject *call_builtin Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *call_function Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *loop_subscript Py_PROTO((PyObject *, PyObject *)); +static int slice_index Py_PROTO((PyObject *, int *)); +static PyObject *apply_slice Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int assign_slice Py_PROTO((PyObject *, PyObject *, + PyObject *, PyObject *)); +static int cmp_exception Py_PROTO((PyObject *, PyObject *)); +static int cmp_member Py_PROTO((PyObject *, PyObject *)); +static PyObject *cmp_outcome Py_PROTO((int, PyObject *, PyObject *)); +static int import_from Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *build_class Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int exec_statement Py_PROTO((PyFrameObject *, + PyObject *, PyObject *, PyObject *)); +static PyObject *find_from_args Py_PROTO((PyFrameObject *, int)); +static void set_exc_info Py_PROTO((PyThreadState *, + PyObject *, PyObject *, PyObject *)); +static void reset_exc_info Py_PROTO((PyThreadState *)); + + +/* Dynamic execution profile */ +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS +static long dxpairs[257][256]; +#define dxp dxpairs[256] +#else +static long dxp[256]; +#endif +#endif + + +#ifdef WITH_THREAD + +#include +#include "thread.h" + +extern int _PyThread_Started; /* Flag for Py_Exit */ + +static type_lock interpreter_lock = 0; +static long main_thread = 0; + +void +PyEval_InitThreads() +{ + if (interpreter_lock) + return; + _PyThread_Started = 1; + interpreter_lock = allocate_lock(); + acquire_lock(interpreter_lock, 1); + main_thread = get_thread_ident(); +} + +#endif + +/* Functions save_thread and restore_thread are always defined so + dynamically loaded modules needn't be compiled separately for use + with and without threads: */ + +PyObject * +PyEval_SaveThread() +{ +#ifdef WITH_THREAD + if (interpreter_lock) { + PyThreadState *tstate = PyThreadState_Swap(NULL); + PyObject *res = tstate ? (PyObject *) (tstate->frame) : NULL; + release_lock(interpreter_lock); + return res; + } +#endif + return NULL; +} + +void +PyEval_RestoreThread(x) + PyObject *x; +{ +#ifdef WITH_THREAD + if (interpreter_lock) { + int err; + err = errno; + acquire_lock(interpreter_lock, 1); + errno = err; + PyThreadState_Swap(x ? ((PyFrameObject *)x)->f_tstate : NULL); + } +#endif +} + + +/* Mechanism whereby asynchronously executing callbacks (e.g. UNIX + signal handlers or Mac I/O completion routines) can schedule calls + to a function to be called synchronously. + The synchronous function is called with one void* argument. + It should return 0 for success or -1 for failure -- failure should + be accompanied by an exception. + + If registry succeeds, the registry function returns 0; if it fails + (e.g. due to too many pending calls) it returns -1 (without setting + an exception condition). + + Note that because registry may occur from within signal handlers, + or other asynchronous events, calling malloc() is unsafe! + +#ifdef WITH_THREAD + Any thread can schedule pending calls, but only the main thread + will execute them. +#endif + + XXX WARNING! ASYNCHRONOUSLY EXECUTING CODE! + There are two possible race conditions: + (1) nested asynchronous registry calls; + (2) registry calls made while pending calls are being processed. + While (1) is very unlikely, (2) is a real possibility. + The current code is safe against (2), but not against (1). + The safety against (2) is derived from the fact that only one + thread (the main thread) ever takes things out of the queue. + + XXX Darn! With the advent of thread state, we should have an array + of pending calls per thread in the thread state! Later... +*/ + +#define NPENDINGCALLS 32 +static struct { + int (*func) Py_PROTO((ANY *)); + ANY *arg; +} pendingcalls[NPENDINGCALLS]; +static volatile int pendingfirst = 0; +static volatile int pendinglast = 0; +static volatile int things_to_do = 0; + +int +Py_AddPendingCall(func, arg) + int (*func) Py_PROTO((ANY *)); + ANY *arg; +{ + static int busy = 0; + int i, j; + /* XXX Begin critical section */ + /* XXX If you want this to be safe against nested + XXX asynchronous calls, you'll have to work harder! */ + if (busy) + return -1; + busy = 1; + i = pendinglast; + j = (i + 1) % NPENDINGCALLS; + if (j == pendingfirst) + return -1; /* Queue full */ + pendingcalls[i].func = func; + pendingcalls[i].arg = arg; + pendinglast = j; + things_to_do = 1; /* Signal main loop */ + busy = 0; + /* XXX End critical section */ + return 0; +} + +int +Py_MakePendingCalls() +{ + static int busy = 0; +#ifdef WITH_THREAD + if (main_thread && get_thread_ident() != main_thread) + return 0; +#endif + if (busy) + return 0; + busy = 1; + things_to_do = 0; + for (;;) { + int i; + int (*func) Py_PROTO((ANY *)); + ANY *arg; + i = pendingfirst; + if (i == pendinglast) + break; /* Queue empty */ + func = pendingcalls[i].func; + arg = pendingcalls[i].arg; + pendingfirst = (i + 1) % NPENDINGCALLS; + if (func(arg) < 0) { + busy = 0; + things_to_do = 1; /* We're not done yet */ + return -1; + } + } + busy = 0; + return 0; +} + + +/* Status code for main loop (reason for stack unwind) */ + +enum why_code { + WHY_NOT, /* No error */ + WHY_EXCEPTION, /* Exception occurred */ + WHY_RERAISE, /* Exception re-raised by 'finally' */ + WHY_RETURN, /* 'return' statement */ + WHY_BREAK /* 'break' statement */ +}; + +static enum why_code do_raise Py_PROTO((PyObject *, PyObject *, PyObject *)); + + +/* Backward compatible interface */ + +PyObject * +PyEval_EvalCode(co, globals, locals) + PyCodeObject *co; + PyObject *globals; + PyObject *locals; +{ + return eval_code2(co, + globals, locals, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + (PyObject *)NULL); +} + + +/* Interpreter main loop */ + +#ifndef MAX_RECURSION_DEPTH +#define MAX_RECURSION_DEPTH 10000 +#endif + +static PyObject * +eval_code2(co, globals, locals, + args, argcount, kws, kwcount, defs, defcount, owner) + PyCodeObject *co; + PyObject *globals; + PyObject *locals; + PyObject **args; + int argcount; + PyObject **kws; /* length: 2*kwcount */ + int kwcount; + PyObject **defs; + int defcount; + PyObject *owner; +{ +#ifdef DXPAIRS + int lastopcode = 0; +#endif + register unsigned char *next_instr; + register int opcode = 0; /* Current opcode */ + register int oparg = 0; /* Current opcode argument, if any */ + register PyObject **stack_pointer; + register enum why_code why; /* Reason for block stack unwind */ + register int err; /* Error status -- nonzero if error */ + register PyObject *x; /* Result object -- NULL if error */ + register PyObject *v; /* Temporary objects popped off stack */ + register PyObject *w; + register PyObject *u; + register PyObject *t; + register PyFrameObject *f; /* Current frame */ + register PyObject **fastlocals = NULL; + PyObject *retval = NULL; /* Return value */ + PyThreadState *tstate = PyThreadState_Get(); +#ifdef LLTRACE + int lltrace; +#endif +#if defined(Py_DEBUG) || defined(LLTRACE) + /* Make it easier to find out where we are with a debugger */ + char *filename = PyString_AsString(co->co_filename); +#endif + +/* Code access macros */ + +#define GETCONST(i) Getconst(f, i) +#define GETNAME(i) Getname(f, i) +#define GETNAMEV(i) Getnamev(f, i) +#define FIRST_INSTR() (GETUSTRINGVALUE(co->co_code)) +#define INSTR_OFFSET() (next_instr - FIRST_INSTR()) +#define NEXTOP() (*next_instr++) +#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) +#define JUMPTO(x) (next_instr = FIRST_INSTR() + (x)) +#define JUMPBY(x) (next_instr += (x)) + +/* Stack manipulation macros */ + +#define STACK_LEVEL() (stack_pointer - f->f_valuestack) +#define EMPTY() (STACK_LEVEL() == 0) +#define TOP() (stack_pointer[-1]) +#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +#define BASIC_POP() (*--stack_pointer) + +#ifdef LLTRACE +#define PUSH(v) (BASIC_PUSH(v), lltrace && prtrace(TOP(), "push")) +#define POP() (lltrace && prtrace(TOP(), "pop"), BASIC_POP()) +#else +#define PUSH(v) BASIC_PUSH(v) +#define POP() BASIC_POP() +#endif + +/* Local variable macros */ + +#define GETLOCAL(i) (fastlocals[i]) +#define SETLOCAL(i, value) do { Py_XDECREF(GETLOCAL(i)); \ + GETLOCAL(i) = value; } while (0) + +/* Start of code */ + + if (tstate == NULL) + Py_FatalError("eval_code2 called without a current thread"); + +#ifdef USE_STACKCHECK + if (tstate->recursion_depth%10 == 0 && PyOS_CheckStack()) { + PyErr_SetString(PyExc_MemoryError, "Stack overflow"); + return NULL; + } +#endif + + if (globals == NULL) { + PyErr_SetString(PyExc_SystemError, "eval_code2: NULL globals"); + return NULL; + } + +#ifdef LLTRACE + lltrace = PyDict_GetItemString(globals, "__lltrace__") != NULL; +#endif + + f = PyFrame_New( + tstate, /*back*/ + co, /*code*/ + globals, /*globals*/ + locals); /*locals*/ + if (f == NULL) + return NULL; + + tstate->frame = f; + fastlocals = f->f_localsplus; + + if (co->co_argcount > 0 || + co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { + int i; + int n = argcount; + PyObject *kwdict = NULL; + if (co->co_flags & CO_VARKEYWORDS) { + kwdict = PyDict_New(); + if (kwdict == NULL) + goto fail; + i = co->co_argcount; + if (co->co_flags & CO_VARARGS) + i++; + SETLOCAL(i, kwdict); + } + if (argcount > co->co_argcount) { + if (!(co->co_flags & CO_VARARGS)) { + PyErr_SetString(PyExc_TypeError, + "too many arguments"); + goto fail; + } + n = co->co_argcount; + } + for (i = 0; i < n; i++) { + x = args[i]; + Py_INCREF(x); + SETLOCAL(i, x); + } + if (co->co_flags & CO_VARARGS) { + u = PyTuple_New(argcount - n); + if (u == NULL) + goto fail; + SETLOCAL(co->co_argcount, u); + for (i = n; i < argcount; i++) { + x = args[i]; + Py_INCREF(x); + PyTuple_SET_ITEM(u, i-n, x); + } + } + for (i = 0; i < kwcount; i++) { + PyObject *keyword = kws[2*i]; + PyObject *value = kws[2*i + 1]; + int j; + /* XXX slow -- speed up using dictionary? */ + for (j = 0; j < co->co_argcount; j++) { + PyObject *nm = PyTuple_GET_ITEM( + co->co_varnames, j); + if (PyObject_Compare(keyword, nm) == 0) + break; + } + if (j >= co->co_argcount) { + if (kwdict == NULL) { + PyErr_Format(PyExc_TypeError, + "unexpected keyword argument: %.400s", + PyString_AsString(keyword)); + goto fail; + } + PyDict_SetItem(kwdict, keyword, value); + } + else { + if (GETLOCAL(j) != NULL) { + PyErr_SetString(PyExc_TypeError, + "keyword parameter redefined"); + goto fail; + } + Py_INCREF(value); + SETLOCAL(j, value); + } + } + if (argcount < co->co_argcount) { + int m = co->co_argcount - defcount; + for (i = argcount; i < m; i++) { + if (GETLOCAL(i) == NULL) { + PyErr_SetString(PyExc_TypeError, + "not enough arguments"); + goto fail; + } + } + if (n > m) + i = n - m; + else + i = 0; + for (; i < defcount; i++) { + if (GETLOCAL(m+i) == NULL) { + PyObject *def = defs[i]; + Py_INCREF(def); + SETLOCAL(m+i, def); + } + } + } + } + else { + if (argcount > 0 || kwcount > 0) { + PyErr_SetString(PyExc_TypeError, + "no arguments expected"); + goto fail; + } + } + + if (tstate->sys_tracefunc != NULL) { + /* tstate->sys_tracefunc, if defined, is a function that + will be called on *every* entry to a code block. + Its return value, if not None, is a function that + will be called at the start of each executed line + of code. (Actually, the function must return + itself in order to continue tracing.) + The trace functions are called with three arguments: + a pointer to the current frame, a string indicating + why the function is called, and an argument which + depends on the situation. The global trace function + (sys.trace) is also called whenever an exception + is detected. */ + if (call_trace(&tstate->sys_tracefunc, + &f->f_trace, f, "call", + Py_None/*XXX how to compute arguments now?*/)) { + /* Trace function raised an error */ + goto fail; + } + } + + if (tstate->sys_profilefunc != NULL) { + /* Similar for sys_profilefunc, except it needn't return + itself and isn't called for "line" events */ + if (call_trace(&tstate->sys_profilefunc, + (PyObject**)0, f, "call", + Py_None/*XXX*/)) { + goto fail; + } + } + + if (++tstate->recursion_depth > MAX_RECURSION_DEPTH) { + --tstate->recursion_depth; + PyErr_SetString(PyExc_RuntimeError, + "Maximum recursion depth exceeded"); + tstate->frame = f->f_back; + Py_DECREF(f); + return NULL; + } + + next_instr = GETUSTRINGVALUE(co->co_code); + stack_pointer = f->f_valuestack; + + why = WHY_NOT; + err = 0; + x = Py_None; /* Not a reference, just anything non-NULL */ + + for (;;) { + /* Do periodic things. Doing this every time through + the loop would add too much overhead, so we do it + only every Nth instruction. We also do it if + ``things_to_do'' is set, i.e. when an asynchronous + event needs attention (e.g. a signal handler or + async I/O handler); see Py_AddPendingCall() and + Py_MakePendingCalls() above. */ + + if (things_to_do || --tstate->ticker < 0) { + tstate->ticker = tstate->sys_checkinterval; + if (things_to_do) { + if (Py_MakePendingCalls() < 0) { + why = WHY_EXCEPTION; + goto on_error; + } + } +#if !defined(HAVE_SIGNAL_H) || defined(macintosh) + /* If we have true signals, the signal handler + will call Py_AddPendingCall() so we don't + have to call sigcheck(). On the Mac and + DOS, alas, we have to call it. */ + if (PyErr_CheckSignals()) { + why = WHY_EXCEPTION; + goto on_error; + } +#endif + +#ifdef WITH_THREAD + if (interpreter_lock) { + /* Give another thread a chance */ + + PyThreadState *tstate = + PyThreadState_Swap(NULL); + release_lock(interpreter_lock); + + /* Other threads may run now */ + + acquire_lock(interpreter_lock, 1); + PyThreadState_Swap(tstate); + } +#endif + } + + /* Extract opcode and argument */ + +#if defined(Py_DEBUG) || defined(LLTRACE) + f->f_lasti = INSTR_OFFSET(); +#endif + + opcode = NEXTOP(); + if (HAS_ARG(opcode)) + oparg = NEXTARG(); +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS + dxpairs[lastopcode][opcode]++; + lastopcode = opcode; +#endif + dxp[opcode]++; +#endif + +#ifdef LLTRACE + /* Instruction tracing */ + + if (lltrace) { + if (HAS_ARG(opcode)) { + printf("%d: %d, %d\n", + (int) (INSTR_OFFSET() - 3), + opcode, oparg); + } + else { + printf("%d: %d\n", + (int) (INSTR_OFFSET() - 1), opcode); + } + } +#endif + + /* Main switch on opcode */ + + switch (opcode) { + + /* BEWARE! + It is essential that any operation that fails sets either + x to NULL, err to nonzero, or why to anything but WHY_NOT, + and that no operation that succeeds does this! */ + + /* case STOP_CODE: this is an error! */ + + case POP_TOP: + v = POP(); + Py_DECREF(v); + continue; + + case ROT_TWO: + v = POP(); + w = POP(); + PUSH(v); + PUSH(w); + continue; + + case ROT_THREE: + v = POP(); + w = POP(); + x = POP(); + PUSH(v); + PUSH(x); + PUSH(w); + continue; + + case DUP_TOP: + v = TOP(); + Py_INCREF(v); + PUSH(v); + continue; + + case UNARY_POSITIVE: + v = POP(); + x = PyNumber_Positive(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_NEGATIVE: + v = POP(); + x = PyNumber_Negative(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_NOT: + v = POP(); + err = PyObject_IsTrue(v); + Py_DECREF(v); + if (err == 0) { + Py_INCREF(Py_True); + PUSH(Py_True); + continue; + } + else if (err > 0) { + Py_INCREF(Py_False); + PUSH(Py_False); + err = 0; + continue; + } + break; + + case UNARY_CONVERT: + v = POP(); + x = PyObject_Repr(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_INVERT: + v = POP(); + x = PyNumber_Invert(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_POWER: + w = POP(); + v = POP(); + x = PyNumber_Power(v, w, Py_None); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_MULTIPLY: + w = POP(); + v = POP(); + x = PyNumber_Multiply(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_DIVIDE: + w = POP(); + v = POP(); + x = PyNumber_Divide(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_MODULO: + w = POP(); + v = POP(); + x = PyNumber_Remainder(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_ADD: + w = POP(); + v = POP(); + x = PyNumber_Add(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_SUBTRACT: + w = POP(); + v = POP(); + x = PyNumber_Subtract(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_SUBSCR: + w = POP(); + v = POP(); + x = PyObject_GetItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_LSHIFT: + w = POP(); + v = POP(); + x = PyNumber_Lshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_RSHIFT: + w = POP(); + v = POP(); + x = PyNumber_Rshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_AND: + w = POP(); + v = POP(); + x = PyNumber_And(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_XOR: + w = POP(); + v = POP(); + x = PyNumber_Xor(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_OR: + w = POP(); + v = POP(); + x = PyNumber_Or(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case SLICE+0: + case SLICE+1: + case SLICE+2: + case SLICE+3: + if ((opcode-SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + x = apply_slice(u, v, w); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case STORE_SLICE+0: + case STORE_SLICE+1: + case STORE_SLICE+2: + case STORE_SLICE+3: + if ((opcode-STORE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-STORE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + t = POP(); + err = assign_slice(u, v, w, t); /* u[v:w] = t */ + Py_DECREF(t); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case DELETE_SLICE+0: + case DELETE_SLICE+1: + case DELETE_SLICE+2: + case DELETE_SLICE+3: + if ((opcode-DELETE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-DELETE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + err = assign_slice(u, v, w, (PyObject *)NULL); + /* del u[v:w] */ + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case STORE_SUBSCR: + w = POP(); + v = POP(); + u = POP(); + /* v[w] = u */ + err = PyObject_SetItem(v, w, u); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case DELETE_SUBSCR: + w = POP(); + v = POP(); + /* del v[w] */ + err = PyObject_DelItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case PRINT_EXPR: + v = POP(); + /* Print value except if procedure result */ + /* Before printing, also assign to '_' */ + if (v != Py_None && + (err = PyDict_SetItemString( + f->f_builtins, "_", v)) == 0 && + !Py_SuppressPrintingFlag) { + Py_FlushLine(); + x = PySys_GetObject("stdout"); + err = PyFile_WriteObject(v, x, 0); + PyFile_SoftSpace(x, 1); + Py_FlushLine(); + } + Py_DECREF(v); + break; + + case PRINT_ITEM: + v = POP(); + w = PySys_GetObject("stdout"); + if (PyFile_SoftSpace(w, 1)) + PyFile_WriteString(" ", w); + err = PyFile_WriteObject(v, w, Py_PRINT_RAW); + if (err == 0 && PyString_Check(v)) { + /* XXX move into writeobject() ? */ + char *s = PyString_AsString(v); + int len = PyString_Size(v); + if (len > 0 && + isspace(Py_CHARMASK(s[len-1])) && + s[len-1] != ' ') + PyFile_SoftSpace(w, 0); + } + Py_DECREF(v); + if (err == 0) continue; + break; + + case PRINT_NEWLINE: + x = PySys_GetObject("stdout"); + if (x == NULL) + PyErr_SetString(PyExc_RuntimeError, + "lost sys.stdout"); + else { + PyFile_WriteString("\n", x); + PyFile_SoftSpace(x, 0); + } + break; + + case BREAK_LOOP: + why = WHY_BREAK; + break; + + case RAISE_VARARGS: + u = v = w = NULL; + switch (oparg) { + case 3: + u = POP(); /* traceback */ + /* Fallthrough */ + case 2: + v = POP(); /* value */ + /* Fallthrough */ + case 1: + w = POP(); /* exc */ + why = do_raise(w, v, u); + break; + default: + PyErr_SetString(PyExc_SystemError, + "bad RAISE_VARARGS oparg"); + why = WHY_EXCEPTION; + break; + } + break; + + case LOAD_LOCALS: + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + Py_INCREF(x); + PUSH(x); + break; + + case RETURN_VALUE: + retval = POP(); + why = WHY_RETURN; + break; + + case EXEC_STMT: + w = POP(); + v = POP(); + u = POP(); + err = exec_statement(f, u, v, w); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case POP_BLOCK: + { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_DECREF(v); + } + } + break; + + case END_FINALLY: + v = POP(); + if (PyInt_Check(v)) { + why = (enum why_code) PyInt_AsLong(v); + if (why == WHY_RETURN) + retval = POP(); + } + else if (PyString_Check(v) || PyClass_Check(v)) { + w = POP(); + u = POP(); + PyErr_Restore(v, w, u); + why = WHY_RERAISE; + break; + } + else if (v != Py_None) { + PyErr_SetString(PyExc_SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; + } + Py_DECREF(v); + break; + + case BUILD_CLASS: + u = POP(); + v = POP(); + w = POP(); + x = build_class(u, v, w); + PUSH(x); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case STORE_NAME: + w = GETNAMEV(oparg); + v = POP(); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + err = PyDict_SetItem(x, w, v); + Py_DECREF(v); + break; + + case DELETE_NAME: + w = GETNAMEV(oparg); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + if ((err = PyDict_DelItem(x, w)) != 0) + PyErr_SetObject(PyExc_NameError, w); + break; + +#ifdef CASE_TOO_BIG + default: switch (opcode) { +#endif + + case UNPACK_TUPLE: + v = POP(); + if (!PyTuple_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "unpack non-tuple"); + why = WHY_EXCEPTION; + } + else if (PyTuple_Size(v) != oparg) { + PyErr_SetString(PyExc_ValueError, + "unpack tuple of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = PyTuple_GET_ITEM(v, oparg); + Py_INCREF(w); + PUSH(w); + } + } + Py_DECREF(v); + break; + + case UNPACK_LIST: + v = POP(); + if (!PyList_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "unpack non-list"); + why = WHY_EXCEPTION; + } + else if (PyList_Size(v) != oparg) { + PyErr_SetString(PyExc_ValueError, + "unpack list of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = PyList_GetItem(v, oparg); + Py_INCREF(w); + PUSH(w); + } + } + Py_DECREF(v); + break; + + case STORE_ATTR: + w = GETNAMEV(oparg); + v = POP(); + u = POP(); + err = PyObject_SetAttr(v, w, u); /* v.w = u */ + Py_DECREF(v); + Py_DECREF(u); + break; + + case DELETE_ATTR: + w = GETNAMEV(oparg); + v = POP(); + err = PyObject_SetAttr(v, w, (PyObject *)NULL); + /* del v.w */ + Py_DECREF(v); + break; + + case STORE_GLOBAL: + w = GETNAMEV(oparg); + v = POP(); + err = PyDict_SetItem(f->f_globals, w, v); + Py_DECREF(v); + break; + + case DELETE_GLOBAL: + w = GETNAMEV(oparg); + if ((err = PyDict_DelItem(f->f_globals, w)) != 0) + PyErr_SetObject(PyExc_NameError, w); + break; + + case LOAD_CONST: + x = GETCONST(oparg); + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_NAME: + w = GETNAMEV(oparg); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + x = PyDict_GetItem(x, w); + if (x == NULL) { + PyErr_Clear(); + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + PyErr_Clear(); + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + PyErr_SetObject( + PyExc_NameError, w); + break; + } + } + } + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_GLOBAL: + w = GETNAMEV(oparg); + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + PyErr_Clear(); + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + PyErr_SetObject(PyExc_NameError, w); + break; + } + } + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_FAST: + x = GETLOCAL(oparg); + if (x == NULL) { + PyErr_SetObject(PyExc_NameError, + PyTuple_GetItem(co->co_varnames, + oparg)); + break; + } + Py_INCREF(x); + PUSH(x); + if (x != NULL) continue; + break; + + case STORE_FAST: + v = POP(); + SETLOCAL(oparg, v); + continue; + + case DELETE_FAST: + SETLOCAL(oparg, NULL); + continue; + + case BUILD_TUPLE: + x = PyTuple_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + PyTuple_SET_ITEM(x, oparg, w); + } + PUSH(x); + continue; + } + break; + + case BUILD_LIST: + x = PyList_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + err = PyList_SetItem(x, oparg, w); + if (err != 0) + break; + } + PUSH(x); + continue; + } + break; + + case BUILD_MAP: + x = PyDict_New(); + PUSH(x); + if (x != NULL) continue; + break; + + case LOAD_ATTR: + w = GETNAMEV(oparg); + v = POP(); + x = PyObject_GetAttr(v, w); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case COMPARE_OP: + w = POP(); + v = POP(); + x = cmp_outcome(oparg, v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case IMPORT_NAME: + w = GETNAMEV(oparg); + x = PyDict_GetItemString(f->f_builtins, "__import__"); + if (x == NULL) { + PyErr_SetString(PyExc_ImportError, + "__import__ not found"); + break; + } + if (PyCFunction_Check(x)) { + u = Py_None; + Py_INCREF(u); + } + else { + u = find_from_args(f, INSTR_OFFSET()); + if (u == NULL) { + x = u; + break; + } + } + w = Py_BuildValue("(OOOO)", + w, + f->f_globals, + f->f_locals == NULL ? + Py_None : f->f_locals, + u); + Py_DECREF(u); + if (w == NULL) { + x = NULL; + break; + } + x = PyEval_CallObject(x, w); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case IMPORT_FROM: + w = GETNAMEV(oparg); + v = TOP(); + PyFrame_FastToLocals(f); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + err = import_from(x, v, w); + PyFrame_LocalsToFast(f, 0); + if (err == 0) continue; + break; + + case JUMP_FORWARD: + JUMPBY(oparg); + continue; + + case JUMP_IF_FALSE: + err = PyObject_IsTrue(TOP()); + if (err > 0) + err = 0; + else if (err == 0) + JUMPBY(oparg); + else + break; + continue; + + case JUMP_IF_TRUE: + err = PyObject_IsTrue(TOP()); + if (err > 0) { + err = 0; + JUMPBY(oparg); + } + else if (err == 0) + ; + else + break; + continue; + + case JUMP_ABSOLUTE: + JUMPTO(oparg); + continue; + + case FOR_LOOP: + /* for v in s: ... + On entry: stack contains s, i. + On exit: stack contains s, i+1, s[i]; + but if loop exhausted: + s, i are popped, and we jump */ + w = POP(); /* Loop index */ + v = POP(); /* Sequence object */ + u = loop_subscript(v, w); + if (u != NULL) { + PUSH(v); + x = PyInt_FromLong(PyInt_AsLong(w)+1); + PUSH(x); + Py_DECREF(w); + PUSH(u); + if (x != NULL) continue; + } + else { + Py_DECREF(v); + Py_DECREF(w); + /* A NULL can mean "s exhausted" + but also an error: */ + if (PyErr_Occurred()) + why = WHY_EXCEPTION; + else { + JUMPBY(oparg); + continue; + } + } + break; + + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); + continue; + + case SET_LINENO: +#ifdef LLTRACE + if (lltrace) + printf("--- %s:%d \n", filename, oparg); +#endif + f->f_lineno = oparg; + if (f->f_trace == NULL) + continue; + /* Trace each line of code reached */ + f->f_lasti = INSTR_OFFSET(); + err = call_trace(&f->f_trace, &f->f_trace, + f, "line", Py_None); + break; + + case CALL_FUNCTION: + { + int na = oparg & 0xff; + int nk = (oparg>>8) & 0xff; + int n = na + 2*nk; + PyObject **pfunc = stack_pointer - n - 1; + PyObject *func = *pfunc; + PyObject *self = NULL; + PyObject *class = NULL; + f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */ + if (PyMethod_Check(func)) { + self = PyMethod_Self(func); + class = PyMethod_Class(func); + func = PyMethod_Function(func); + Py_INCREF(func); + if (self != NULL) { + Py_INCREF(self); + Py_DECREF(*pfunc); + *pfunc = self; + na++; + n++; + } + else { + /* Unbound methods must be + called with an instance of + the class (or a derived + class) as first argument */ + if (na > 0 && + (self = stack_pointer[-n]) + != NULL && + PyInstance_Check(self) && + PyClass_IsSubclass( + (PyObject *) + (((PyInstanceObject *)self) + ->in_class), + class)) + /* Handy-dandy */ ; + else { + PyErr_SetString( + PyExc_TypeError, + "unbound method must be called with class instance 1st argument"); + x = NULL; + break; + } + } + } + else + Py_INCREF(func); + if (PyFunction_Check(func)) { + PyObject *co = PyFunction_GetCode(func); + PyObject *globals = + PyFunction_GetGlobals(func); + PyObject *argdefs = + PyFunction_GetDefaults(func); + PyObject **d; + int nd; + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = ((PyTupleObject *)argdefs) -> + ob_size; + } + else { + d = NULL; + nd = 0; + } + x = eval_code2( + (PyCodeObject *)co, + globals, (PyObject *)NULL, + stack_pointer-n, na, + stack_pointer-2*nk, nk, + d, nd, + class); + } + else { + PyObject *args = PyTuple_New(na); + PyObject *kwdict = NULL; + if (args == NULL) { + x = NULL; + break; + } + if (nk > 0) { + kwdict = PyDict_New(); + if (kwdict == NULL) { + x = NULL; + break; + } + err = 0; + while (--nk >= 0) { + PyObject *value = POP(); + PyObject *key = POP(); + err = PyDict_SetItem( + kwdict, key, value); + Py_DECREF(key); + Py_DECREF(value); + if (err) + break; + } + if (err) { + Py_DECREF(args); + Py_DECREF(kwdict); + break; + } + } + while (--na >= 0) { + w = POP(); + PyTuple_SET_ITEM(args, na, w); + } + x = PyEval_CallObjectWithKeywords( + func, args, kwdict); + Py_DECREF(args); + Py_XDECREF(kwdict); + } + Py_DECREF(func); + while (stack_pointer > pfunc) { + w = POP(); + Py_DECREF(w); + } + PUSH(x); + if (x != NULL) continue; + break; + } + + case MAKE_FUNCTION: + v = POP(); /* code object */ + x = PyFunction_New(v, f->f_globals); + Py_DECREF(v); + /* XXX Maybe this should be a separate opcode? */ + if (x != NULL && oparg > 0) { + v = PyTuple_New(oparg); + if (v == NULL) { + Py_DECREF(x); + x = NULL; + break; + } + while (--oparg >= 0) { + w = POP(); + PyTuple_SET_ITEM(v, oparg, w); + } + err = PyFunction_SetDefaults(x, v); + Py_DECREF(v); + } + PUSH(x); + break; + + case BUILD_SLICE: + if (oparg == 3) + w = POP(); + else + w = NULL; + v = POP(); + u = POP(); + x = PySlice_New(u, v, w); + Py_DECREF(u); + Py_DECREF(v); + Py_XDECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + + default: + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + f->f_lineno, opcode); + PyErr_SetString(PyExc_SystemError, "unknown opcode"); + why = WHY_EXCEPTION; + break; + +#ifdef CASE_TOO_BIG + } +#endif + + } /* switch */ + + on_error: + + /* Quickly continue if no error occurred */ + + if (why == WHY_NOT) { + if (err == 0 && x != NULL) { +#ifdef CHECKEXC + if (PyErr_Occurred()) + fprintf(stderr, + "XXX undetected error\n"); + else +#endif + continue; /* Normal, fast path */ + } + why = WHY_EXCEPTION; + x = Py_None; + err = 0; + } + +#ifdef CHECKEXC + /* Double-check exception status */ + + if (why == WHY_EXCEPTION || why == WHY_RERAISE) { + if (!PyErr_Occurred()) { + fprintf(stderr, "XXX ghost error\n"); + PyErr_SetString(PyExc_SystemError, + "ghost error"); + why = WHY_EXCEPTION; + } + } + else { + if (PyErr_Occurred()) { + fprintf(stderr, + "XXX undetected error (why=%d)\n", + why); + why = WHY_EXCEPTION; + } + } +#endif + + /* Log traceback info if this is a real exception */ + + if (why == WHY_EXCEPTION) { + f->f_lasti = INSTR_OFFSET() - 1; + if (HAS_ARG(opcode)) + f->f_lasti -= 2; + PyTraceBack_Here(f); + + if (f->f_trace) + call_exc_trace(&f->f_trace, &f->f_trace, f); + if (tstate->sys_profilefunc) + call_exc_trace(&tstate->sys_profilefunc, + (PyObject**)0, f); +} + + /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ + + if (why == WHY_RERAISE) + why = WHY_EXCEPTION; + + /* Unwind stacks if a (pseudo) exception occurred */ + + while (why != WHY_NOT && f->f_iblock > 0) { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_XDECREF(v); + } + if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + if (b->b_type == SETUP_FINALLY || + (b->b_type == SETUP_EXCEPT && + why == WHY_EXCEPTION)) { + if (why == WHY_EXCEPTION) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (val == NULL) { + val = Py_None; + Py_INCREF(val); + } + /* Make the raw exception data + available to the handler, + so a program can emulate the + Python main loop. Don't do + this for 'finally'. */ + if (b->b_type == SETUP_EXCEPT) { + set_exc_info(tstate, + exc, val, tb); + } + PUSH(tb); + PUSH(val); + PUSH(exc); + } + else { + if (why == WHY_RETURN) + PUSH(retval); + v = PyInt_FromLong((long)why); + PUSH(v); + } + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + } /* unwind stack */ + + /* End the loop if we still have an error (or return) */ + + if (why != WHY_NOT) + break; + + } /* main loop */ + + /* Pop remaining stack entries */ + + while (!EMPTY()) { + v = POP(); + Py_XDECREF(v); + } + + if (why != WHY_RETURN) + retval = NULL; + + if (f->f_trace) { + if (why == WHY_RETURN) { + if (call_trace(&f->f_trace, &f->f_trace, f, + "return", retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + } + + if (tstate->sys_profilefunc && why == WHY_RETURN) { + if (call_trace(&tstate->sys_profilefunc, (PyObject**)0, + f, "return", retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + + reset_exc_info(tstate); + + --tstate->recursion_depth; + + fail: /* Jump here from prelude on failure */ + + /* Restore previous frame and release the current one */ + + tstate->frame = f->f_back; + Py_DECREF(f); + + return retval; +} + +static void +set_exc_info(tstate, type, value, tb) + PyThreadState *tstate; + PyObject *type; + PyObject *value; + PyObject *tb; +{ + PyFrameObject *frame; + frame = tstate->frame; + if (frame->f_exc_type == NULL) { + /* This frame didn't catch an exception before */ + /* Save previous exception of this thread in this frame */ + Py_XDECREF(frame->f_exc_type); + Py_XDECREF(frame->f_exc_value); + Py_XDECREF(frame->f_exc_traceback); + if (tstate->exc_type == NULL) { + Py_INCREF(Py_None); + tstate->exc_type = Py_None; + } + Py_XINCREF(tstate->exc_type); + Py_XINCREF(tstate->exc_value); + Py_XINCREF(tstate->exc_traceback); + frame->f_exc_type = tstate->exc_type; + frame->f_exc_value = tstate->exc_value; + frame->f_exc_traceback = tstate->exc_traceback; + } + /* Set new exception for this thread */ + Py_XINCREF(type); + Py_XINCREF(value); + Py_XINCREF(tb); + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + /* For b/w compatibility */ + PySys_SetObject("exc_type", type); + PySys_SetObject("exc_value", value); + PySys_SetObject("exc_traceback", tb); +} + +static void +reset_exc_info(tstate) + PyThreadState *tstate; +{ + PyFrameObject *frame; + frame = tstate->frame; + if (frame->f_exc_type != NULL) { + /* This frame caught an exception */ + Py_XDECREF(tstate->exc_type); + Py_XDECREF(tstate->exc_value); + Py_XDECREF(tstate->exc_traceback); + Py_XINCREF(frame->f_exc_type); + Py_XINCREF(frame->f_exc_value); + Py_XINCREF(frame->f_exc_traceback); + tstate->exc_type = frame->f_exc_type; + tstate->exc_value = frame->f_exc_value; + tstate->exc_traceback = frame->f_exc_traceback; + /* For b/w compatibility */ + PySys_SetObject("exc_type", frame->f_exc_type); + PySys_SetObject("exc_value", frame->f_exc_value); + PySys_SetObject("exc_traceback", frame->f_exc_traceback); + } + Py_XDECREF(frame->f_exc_type); + Py_XDECREF(frame->f_exc_value); + Py_XDECREF(frame->f_exc_traceback); + frame->f_exc_type = NULL; + frame->f_exc_value = NULL; + frame->f_exc_traceback = NULL; +} + +/* Logic for the raise statement (too complicated for inlining). + This *consumes* a reference count to each of its arguments. */ +static enum why_code +do_raise(type, value, tb) + PyObject *type, *value, *tb; +{ + /* We support the following forms of raise: + raise , + raise , + raise , None + raise , + raise , None + raise , + raise , None + + An omitted second argument is the same as None. + + In addition, raise , is the same as + raising the tuple's first item (and it better have one!); + this rule is applied recursively. + + Finally, an optional third argument can be supplied, which + gives the traceback to be substituted (useful when + re-raising an exception after examining it). */ + + /* First, check the traceback argument, replacing None with + NULL. */ + if (tb == Py_None) { + Py_DECREF(tb); + tb = NULL; + } + else if (tb != NULL && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise 3rd arg must be traceback or None"); + goto raise_error; + } + + /* Next, replace a missing value with None */ + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + + /* Next, repeatedly, replace a tuple exception with its first item */ + while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { + PyObject *tmp = type; + type = PyTuple_GET_ITEM(type, 0); + Py_INCREF(type); + Py_DECREF(tmp); + } + + /* Now switch on the exception's type */ + if (PyString_Check(type)) { + ; + } + else if (PyClass_Check(type)) { + /* Raising a class. If the value is an instance, it + better be an instance of the class. If it is not, + it will be used to create an instance. */ + if (PyInstance_Check(value)) { + PyObject *inclass = (PyObject*) + (((PyInstanceObject*)value)->in_class); + if (!PyClass_IsSubclass(inclass, type)) { + PyErr_SetString(PyExc_TypeError, + "raise , requires that is a member of "); + goto raise_error; + } + } + else { + /* Go instantiate the class */ + PyObject *args, *res; + if (value == Py_None) + args = Py_BuildValue("()"); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } + else + args = Py_BuildValue("(O)", value); + if (args == NULL) + goto raise_error; + res = PyEval_CallObject(type, args); + Py_DECREF(args); + if (res == NULL) + goto raise_error; + Py_DECREF(value); + value = res; + } + } + else if (PyInstance_Check(type)) { + /* Raising an instance. The value should be a dummy. */ + if (value != Py_None) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + else { + /* Normalize to raise , */ + Py_DECREF(value); + value = type; + type = (PyObject*) ((PyInstanceObject*)type)->in_class; + Py_INCREF(type); + } + } + else { + /* Not something you can raise. You get an exception + anyway, just not what you specified :-) */ + PyErr_SetString(PyExc_TypeError, + "exceptions must be strings, classes, or instances"); + goto raise_error; + } + PyErr_Restore(type, value, tb); + if (tb == NULL) + return WHY_EXCEPTION; + else + return WHY_RERAISE; + raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return WHY_EXCEPTION; +} + +#ifdef LLTRACE +static int +prtrace(v, str) + PyObject *v; + char *str; +{ + printf("%s ", str); + if (PyObject_Print(v, stdout, 0) != 0) + PyErr_Clear(); /* Don't know what else to do */ + printf("\n"); +} +#endif + +static void +call_exc_trace(p_trace, p_newtrace, f) + PyObject **p_trace, **p_newtrace; + PyFrameObject *f; +{ + PyObject *type, *value, *traceback, *arg; + int err; + PyErr_Fetch(&type, &value, &traceback); + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + arg = Py_BuildValue("(OOO)", type, value, traceback); + if (arg == NULL) { + PyErr_Restore(type, value, traceback); + return; + } + err = call_trace(p_trace, p_newtrace, f, "exception", arg); + Py_DECREF(arg); + if (err == 0) + PyErr_Restore(type, value, traceback); + else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } +} + +static int +call_trace(p_trace, p_newtrace, f, msg, arg) + PyObject **p_trace; /* in/out; may not be NULL; + may not point to NULL variable initially */ + PyObject **p_newtrace; /* in/out; may be NULL; + may point to NULL variable; + may be same variable as p_newtrace */ + PyFrameObject *f; + char *msg; + PyObject *arg; +{ + PyThreadState *tstate = f->f_tstate; + PyObject *args, *what; + PyObject *res = NULL; + + if (tstate->tracing) { + /* Don't do recursive traces */ + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + *p_newtrace = NULL; + } + return 0; + } + + args = PyTuple_New(3); + if (args == NULL) + goto Py_Cleanup; + what = PyString_FromString(msg); + if (what == NULL) + goto Py_Cleanup; + Py_INCREF(f); + PyTuple_SET_ITEM(args, 0, (PyObject *)f); + PyTuple_SET_ITEM(args, 1, what); + if (arg == NULL) + arg = Py_None; + Py_INCREF(arg); + PyTuple_SET_ITEM(args, 2, arg); + tstate->tracing++; + PyFrame_FastToLocals(f); + res = PyEval_CallObject(*p_trace, args); /* May clear *p_trace! */ + PyFrame_LocalsToFast(f, 1); + tstate->tracing--; + Py_Cleanup: + Py_XDECREF(args); + if (res == NULL) { + /* The trace proc raised an exception */ + PyTraceBack_Here(f); + Py_XDECREF(*p_trace); + *p_trace = NULL; + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + *p_newtrace = NULL; + } + return -1; + } + else { + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + if (res == Py_None) + *p_newtrace = NULL; + else { + Py_INCREF(res); + *p_newtrace = res; + } + } + Py_DECREF(res); + return 0; + } +} + +PyObject * +PyEval_GetBuiltins() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + if (current_frame == NULL) + return PyBuiltin_GetModule(); + else + return current_frame->f_builtins; +} + +PyObject * +PyEval_GetLocals() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + if (current_frame == NULL) + return NULL; + PyFrame_FastToLocals(current_frame); + return current_frame->f_locals; +} + +PyObject * +PyEval_GetGlobals() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + if (current_frame == NULL) + return NULL; + else + return current_frame->f_globals; +} + +PyObject * +PyEval_GetFrame() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + return (PyObject *)current_frame; +} + +int +PyEval_GetRestricted() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + return current_frame == NULL ? 0 : current_frame->f_restricted; +} + +void +Py_FlushLine() +{ + PyObject *f = PySys_GetObject("stdout"); + if (PyFile_SoftSpace(f, 0)) + PyFile_WriteString("\n", f); +} + + +/* External interface to call any callable object. + The arg must be a tuple or NULL. */ + +PyObject * +PyEval_CallObject(func, arg) + PyObject *func; + PyObject *arg; +{ + return PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL); +} + +PyObject * +PyEval_CallObjectWithKeywords(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + ternaryfunc call; + PyObject *result; + + if (arg == NULL) + arg = PyTuple_New(0); + else if (!PyTuple_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "argument list must be a tuple"); + return NULL; + } + else + Py_INCREF(arg); + + if (kw != NULL && !PyDict_Check(kw)) { + PyErr_SetString(PyExc_TypeError, + "keyword list must be a dictionary"); + return NULL; + } + + if ((call = func->ob_type->tp_call) != NULL) + result = (*call)(func, arg, kw); + else if (PyMethod_Check(func) || PyFunction_Check(func)) + result = call_function(func, arg, kw); + else + result = call_builtin(func, arg, kw); + + Py_DECREF(arg); + + if (result == NULL && !PyErr_Occurred()) + PyErr_SetString(PyExc_SystemError, + "NULL result without error in call_object"); + + return result; +} + +static PyObject * +call_builtin(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + if (PyCFunction_Check(func)) { + PyCFunction meth = PyCFunction_GetFunction(func); + PyObject *self = PyCFunction_GetSelf(func); + int flags = PyCFunction_GetFlags(func); + if (!(flags & METH_VARARGS)) { + int size = PyTuple_Size(arg); + if (size == 1) + arg = PyTuple_GET_ITEM(arg, 0); + else if (size == 0) + arg = NULL; + } + if (flags & METH_KEYWORDS) + return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); + if (kw != NULL && PyDict_Size(kw) != 0) { + PyErr_SetString(PyExc_TypeError, + "this function takes no keyword arguments"); + return NULL; + } + return (*meth)(self, arg); + } + if (PyClass_Check(func)) { + return PyInstance_New(func, arg, kw); + } + if (PyInstance_Check(func)) { + PyObject *res, *call = PyObject_GetAttrString(func,"__call__"); + if (call == NULL) { + PyErr_Clear(); + PyErr_SetString(PyExc_AttributeError, + "no __call__ method defined"); + return NULL; + } + res = PyEval_CallObjectWithKeywords(call, arg, kw); + Py_DECREF(call); + return res; + } + PyErr_SetString(PyExc_TypeError, "call of non-function"); + return NULL; +} + +static PyObject * +call_function(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + PyObject *class = NULL; /* == owner */ + PyObject *argdefs; + PyObject **d, **k; + int nk, nd; + PyObject *result; + + if (kw != NULL && !PyDict_Check(kw)) { + PyErr_BadInternalCall(); + return NULL; + } + + if (PyMethod_Check(func)) { + PyObject *self = PyMethod_Self(func); + class = PyMethod_Class(func); + func = PyMethod_Function(func); + if (self == NULL) { + /* Unbound methods must be called with an instance of + the class (or a derived class) as first argument */ + if (PyTuple_Size(arg) >= 1) { + self = PyTuple_GET_ITEM(arg, 0); + if (self != NULL && + PyInstance_Check(self) && + PyClass_IsSubclass((PyObject *) + (((PyInstanceObject *)self)->in_class), + class)) + /* Handy-dandy */ ; + else + self = NULL; + } + if (self == NULL) { + PyErr_SetString(PyExc_TypeError, + "unbound method must be called with class instance 1st argument"); + return NULL; + } + Py_INCREF(arg); + } + else { + int argcount = PyTuple_Size(arg); + PyObject *newarg = PyTuple_New(argcount + 1); + int i; + if (newarg == NULL) + return NULL; + Py_INCREF(self); + PyTuple_SET_ITEM(newarg, 0, self); + for (i = 0; i < argcount; i++) { + PyObject *v = PyTuple_GET_ITEM(arg, i); + Py_XINCREF(v); + PyTuple_SET_ITEM(newarg, i+1, v); + } + arg = newarg; + } + } + else { + if (!PyFunction_Check(func)) { + PyErr_SetString(PyExc_TypeError, + "call of non-function"); + return NULL; + } + Py_INCREF(arg); + } + + argdefs = PyFunction_GetDefaults(func); + if (argdefs != NULL && PyTuple_Check(argdefs)) { + d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0); + nd = PyTuple_Size(argdefs); + } + else { + d = NULL; + nd = 0; + } + + if (kw != NULL) { + int pos, i; + nk = PyDict_Size(kw); + k = PyMem_NEW(PyObject *, 2*nk); + if (k == NULL) { + PyErr_NoMemory(); + Py_DECREF(arg); + return NULL; + } + pos = i = 0; + while (PyDict_Next(kw, &pos, &k[i], &k[i+1])) + i += 2; + nk = i/2; + /* XXX This is broken if the caller deletes dict items! */ + } + else { + k = NULL; + nk = 0; + } + + result = eval_code2( + (PyCodeObject *)PyFunction_GetCode(func), + PyFunction_GetGlobals(func), (PyObject *)NULL, + &PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg), + k, nk, + d, nd, + class); + + Py_DECREF(arg); + PyMem_XDEL(k); + + return result; +} + +#define SLICE_ERROR_MSG \ + "standard sequence type does not support step size other than one" + +static PyObject * +loop_subscript(v, w) + PyObject *v, *w; +{ + PySequenceMethods *sq = v->ob_type->tp_as_sequence; + int i; + if (sq == NULL) { + PyErr_SetString(PyExc_TypeError, "loop over non-sequence"); + return NULL; + } + i = PyInt_AsLong(w); + v = (*sq->sq_item)(v, i); + if (v) + return v; + if (PyErr_Occurred() == PyExc_IndexError) + PyErr_Clear(); + return NULL; +} + +static int +slice_index(v, pi) + PyObject *v; + int *pi; +{ + if (v != NULL) { + long x; + if (!PyInt_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "slice index must be int"); + return -1; + } + x = PyInt_AsLong(v); + /* Truncate -- very long indices are truncated anyway */ + if (x > INT_MAX) + x = INT_MAX; + else if (x < -INT_MAX) + x = 0; + *pi = x; + } + return 0; +} + +static PyObject * +apply_slice(u, v, w) /* return u[v:w] */ + PyObject *u, *v, *w; +{ + int ilow = 0, ihigh = INT_MAX; + if (slice_index(v, &ilow) != 0) + return NULL; + if (slice_index(w, &ihigh) != 0) + return NULL; + return PySequence_GetSlice(u, ilow, ihigh); +} + +static int +assign_slice(u, v, w, x) /* u[v:w] = x */ + PyObject *u, *v, *w, *x; +{ + int ilow = 0, ihigh = INT_MAX; + if (slice_index(v, &ilow) != 0) + return -1; + if (slice_index(w, &ihigh) != 0) + return -1; + if (x == NULL) + return PySequence_DelSlice(u, ilow, ihigh); + else + return PySequence_SetSlice(u, ilow, ihigh, x); +} + +static int +cmp_exception(err, v) + PyObject *err, *v; +{ + if (PyTuple_Check(v)) { + int i, n; + n = PyTuple_Size(v); + for (i = 0; i < n; i++) { + /* Test recursively */ + if (cmp_exception(err, PyTuple_GET_ITEM(v, i))) + return 1; + } + return 0; + } + if (PyClass_Check(v) && PyClass_Check(err)) + return PyClass_IsSubclass(err, v); + return err == v; +} + +static int +cmp_member(v, w) + PyObject *v, *w; +{ + int i, cmp; + PyObject *x; + PySequenceMethods *sq; + /* Special case for char in string */ + if (PyString_Check(w)) { + register char *s, *end; + register char c; + if (!PyString_Check(v) || PyString_Size(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "string member test needs char left operand"); + return -1; + } + c = PyString_AsString(v)[0]; + s = PyString_AsString(w); + end = s + PyString_Size(w); + while (s < end) { + if (c == *s++) + return 1; + } + return 0; + } + sq = w->ob_type->tp_as_sequence; + if (sq == NULL) { + PyErr_SetString(PyExc_TypeError, + "'in' or 'not in' needs sequence right argument"); + return -1; + } + for (i = 0; ; i++) { + x = (*sq->sq_item)(w, i); + if (x == NULL) { + if (PyErr_Occurred() == PyExc_IndexError) { + PyErr_Clear(); + break; + } + return -1; + } + cmp = PyObject_Compare(v, x); + Py_XDECREF(x); + if (cmp == 0) + return 1; + } + return 0; +} + +static PyObject * +cmp_outcome(op, v, w) + int op; + register PyObject *v; + register PyObject *w; +{ + register int cmp; + register int res = 0; + switch (op) { + case IS: + case IS_NOT: + res = (v == w); + if (op == (int) IS_NOT) + res = !res; + break; + case IN: + case NOT_IN: + res = cmp_member(v, w); + if (res < 0) + return NULL; + if (op == (int) NOT_IN) + res = !res; + break; + case EXC_MATCH: + res = cmp_exception(v, w); + break; + default: + cmp = PyObject_Compare(v, w); + switch (op) { + case LT: res = cmp < 0; break; + case LE: res = cmp <= 0; break; + case EQ: res = cmp == 0; break; + case NE: res = cmp != 0; break; + case GT: res = cmp > 0; break; + case GE: res = cmp >= 0; break; + /* XXX no default? (res is initialized to 0 though) */ + } + } + v = res ? Py_True : Py_False; + Py_INCREF(v); + return v; +} + +static int +import_from(locals, v, name) + PyObject *locals; + PyObject *v; + PyObject *name; +{ + PyObject *w, *x; + if (!PyModule_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "import-from requires module object"); + return -1; + } + w = PyModule_GetDict(v); + if (PyString_AsString(name)[0] == '*') { + int pos, err; + PyObject *name, *value; + pos = 0; + while (PyDict_Next(w, &pos, &name, &value)) { + if (!PyString_Check(name) || + PyString_AsString(name)[0] == '_') + continue; + Py_INCREF(value); + err = PyDict_SetItem(locals, name, value); + Py_DECREF(value); + if (err != 0) + return -1; + } + return 0; + } + else { + x = PyDict_GetItem(w, name); + if (x == NULL) { + char buf[250]; + sprintf(buf, "cannot import name %.230s", + PyString_AsString(name)); + PyErr_SetString(PyExc_ImportError, buf); + return -1; + } + else + return PyDict_SetItem(locals, name, x); + } +} + +static PyObject * +build_class(methods, bases, name) + PyObject *methods; /* dictionary */ + PyObject *bases; /* tuple containing classes */ + PyObject *name; /* string */ +{ + int i; + if (!PyTuple_Check(bases)) { + PyErr_SetString(PyExc_SystemError, + "build_class with non-tuple bases"); + return NULL; + } + if (!PyDict_Check(methods)) { + PyErr_SetString(PyExc_SystemError, + "build_class with non-dictionary"); + return NULL; + } + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_SystemError, + "build_class witn non-string name"); + return NULL; + } + for (i = PyTuple_Size(bases); --i >= 0; ) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + if (!PyClass_Check(base)) { + /* Call the base's *type*, if it is callable. + This code is a hook for Donald Beaudry's + and Jim Fulton's type extensions. In + unexended Python it will never be triggered + since its types are not callable. */ + if (base->ob_type->ob_type->tp_call) { + PyObject *args; + PyObject *class; + args = Py_BuildValue("(OOO)", + name, bases, methods); + class = PyEval_CallObject( + (PyObject *)base->ob_type, args); + Py_DECREF(args); + return class; + } + PyErr_SetString(PyExc_TypeError, + "base is not a class object"); + return NULL; + } + } + return PyClass_New(bases, methods, name); +} + +static int +exec_statement(f, prog, globals, locals) + PyFrameObject *f; + PyObject *prog; + PyObject *globals; + PyObject *locals; +{ + char *s; + int n; + PyObject *v; + int plain = 0; + + if (PyTuple_Check(prog) && globals == Py_None && locals == Py_None && + ((n = PyTuple_Size(prog)) == 2 || n == 3)) { + /* Backward compatibility hack */ + globals = PyTuple_GetItem(prog, 1); + if (n == 3) + locals = PyTuple_GetItem(prog, 2); + prog = PyTuple_GetItem(prog, 0); + } + if (globals == Py_None) { + globals = PyEval_GetGlobals(); + if (locals == Py_None) { + locals = PyEval_GetLocals(); + plain = 1; + } + } + else if (locals == Py_None) + locals = globals; + if (!PyString_Check(prog) && + !PyCode_Check(prog) && + !PyFile_Check(prog)) { + PyErr_SetString(PyExc_TypeError, + "exec 1st arg must be string, code or file object"); + return -1; + } + if (!PyDict_Check(globals) || !PyDict_Check(locals)) { + PyErr_SetString(PyExc_TypeError, + "exec 2nd/3rd args must be dict or None"); + return -1; + } + if (PyDict_GetItemString(globals, "__builtins__") == NULL) + PyDict_SetItemString(globals, "__builtins__", f->f_builtins); + if (PyCode_Check(prog)) { + if (PyEval_EvalCode((PyCodeObject *) prog, + globals, locals) == NULL) + return -1; + return 0; + } + if (PyFile_Check(prog)) { + FILE *fp = PyFile_AsFile(prog); + char *name = PyString_AsString(PyFile_Name(prog)); + if (PyRun_File(fp, name, Py_file_input, + globals, locals) == NULL) + return -1; + return 0; + } + s = PyString_AsString(prog); + if ((int)strlen(s) != PyString_Size(prog)) { + PyErr_SetString(PyExc_ValueError, + "embedded '\\0' in exec string"); + return -1; + } + v = PyRun_String(s, Py_file_input, globals, locals); + if (v == NULL) + return -1; + Py_DECREF(v); + if (plain) + PyFrame_LocalsToFast(f, 0); + return 0; +} + +/* Hack for ni.py */ +static PyObject * +find_from_args(f, nexti) + PyFrameObject *f; + int nexti; +{ + int opcode; + int oparg; + PyObject *list, *name; + unsigned char *next_instr; + + next_instr = GETUSTRINGVALUE(f->f_code->co_code) + nexti; + opcode = (*next_instr++); + if (opcode != IMPORT_FROM) { + Py_INCREF(Py_None); + return Py_None; + } + + list = PyList_New(0); + if (list == NULL) + return NULL; + + do { + oparg = (next_instr[1]<<8) + next_instr[0]; + next_instr += 2; + name = Getnamev(f, oparg); + if (PyList_Append(list, name) < 0) { + Py_DECREF(list); + break; + } + opcode = (*next_instr++); + } while (opcode == IMPORT_FROM); + + return list; +} + + +#ifdef DYNAMIC_EXECUTION_PROFILE + +PyObject * +getarray(a) + long a[256]; +{ + int i; + PyObject *l = PyList_New(256); + if (l == NULL) return NULL; + for (i = 0; i < 256; i++) { + PyObject *x = PyInt_FromLong(a[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + for (i = 0; i < 256; i++) + a[i] = 0; + return l; +} + +PyObject * +_Py_GetDXProfile(self, args) + PyObject *self, *args; +{ +#ifndef DXPAIRS + return getarray(dxp); +#else + int i; + PyObject *l = PyList_New(257); + if (l == NULL) return NULL; + for (i = 0; i < 257; i++) { + PyObject *x = getarray(dxpairs[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + return l; +#endif +} + +#endif diff --git a/src/main/resource/testFiles/cpython/revFiles/f62026_71eb864_Python#ceval.c b/src/main/resource/testFiles/cpython/revFiles/f62026_71eb864_Python#ceval.c new file mode 100644 index 0000000..4c1bf2f --- /dev/null +++ b/src/main/resource/testFiles/cpython/revFiles/f62026_71eb864_Python#ceval.c @@ -0,0 +1,2888 @@ +/*********************************************************** +Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, +The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI or Corporation for National Research Initiatives or +CNRI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +While CWI is the initial source for this software, a modified version +is made available by the Corporation for National Research Initiatives +(CNRI) at the Internet address ftp://ftp.python.org. + +STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH +CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Execute compiled code */ + +/* XXX TO DO: + XXX how to pass arguments to call_trace? + XXX speed up searching for keywords by using a dictionary + XXX document it! + */ + +#include "Python.h" + +#include "compile.h" +#include "frameobject.h" +#include "eval.h" +#include "opcode.h" + +#include + +#ifdef HAVE_LIMITS_H +#include +#else +#define INT_MAX 2147483647 +#endif + +/* Turn this on if your compiler chokes on the big switch: */ +/* #define CASE_TOO_BIG 1 */ + +#ifdef Py_DEBUG +/* For debugging the interpreter: */ +#define LLTRACE 1 /* Low-level trace feature */ +#define CHECKEXC 1 /* Double-check exception checking */ +#endif + + +/* Forward declarations */ + +static PyObject *eval_code2 Py_PROTO((PyCodeObject *, + PyObject *, PyObject *, + PyObject **, int, + PyObject **, int, + PyObject **, int, + PyObject *)); +#ifdef LLTRACE +static int prtrace Py_PROTO((PyObject *, char *)); +#endif +static void call_exc_trace Py_PROTO((PyObject **, PyObject**, + PyFrameObject *)); +static int call_trace Py_PROTO((PyObject **, PyObject **, + PyFrameObject *, char *, PyObject *)); +static PyObject *call_builtin Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *call_function Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *loop_subscript Py_PROTO((PyObject *, PyObject *)); +static int slice_index Py_PROTO((PyObject *, int *)); +static PyObject *apply_slice Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int assign_slice Py_PROTO((PyObject *, PyObject *, + PyObject *, PyObject *)); +static PyObject *cmp_outcome Py_PROTO((int, PyObject *, PyObject *)); +static int import_from Py_PROTO((PyObject *, PyObject *, PyObject *)); +static PyObject *build_class Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int exec_statement Py_PROTO((PyFrameObject *, + PyObject *, PyObject *, PyObject *)); +static PyObject *find_from_args Py_PROTO((PyFrameObject *, int)); +static void set_exc_info Py_PROTO((PyThreadState *, + PyObject *, PyObject *, PyObject *)); +static void reset_exc_info Py_PROTO((PyThreadState *)); + + +/* Dynamic execution profile */ +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS +static long dxpairs[257][256]; +#define dxp dxpairs[256] +#else +static long dxp[256]; +#endif +#endif + + +#ifdef WITH_THREAD + +#ifndef DONT_HAVE_ERRNO_H +#include +#endif +#include "pythread.h" + +extern int _PyThread_Started; /* Flag for Py_Exit */ + +static PyThread_type_lock interpreter_lock = 0; +static long main_thread = 0; + +void +PyEval_InitThreads() +{ + if (interpreter_lock) + return; + _PyThread_Started = 1; + interpreter_lock = PyThread_allocate_lock(); + PyThread_acquire_lock(interpreter_lock, 1); + main_thread = PyThread_get_thread_ident(); +} + +void +PyEval_AcquireLock() +{ + PyThread_acquire_lock(interpreter_lock, 1); +} + +void +PyEval_ReleaseLock() +{ + PyThread_release_lock(interpreter_lock); +} + +void +PyEval_AcquireThread(tstate) + PyThreadState *tstate; +{ + if (tstate == NULL) + Py_FatalError("PyEval_AcquireThread: NULL new thread state"); + PyThread_acquire_lock(interpreter_lock, 1); + if (PyThreadState_Swap(tstate) != NULL) + Py_FatalError( + "PyEval_AcquireThread: non-NULL old thread state"); +} + +void +PyEval_ReleaseThread(tstate) + PyThreadState *tstate; +{ + if (tstate == NULL) + Py_FatalError("PyEval_ReleaseThread: NULL thread state"); + if (PyThreadState_Swap(NULL) != tstate) + Py_FatalError("PyEval_ReleaseThread: wrong thread state"); + PyThread_release_lock(interpreter_lock); +} +#endif + +/* Functions save_thread and restore_thread are always defined so + dynamically loaded modules needn't be compiled separately for use + with and without threads: */ + +PyThreadState * +PyEval_SaveThread() +{ + PyThreadState *tstate = PyThreadState_Swap(NULL); + if (tstate == NULL) + Py_FatalError("PyEval_SaveThread: NULL tstate"); +#ifdef WITH_THREAD + if (interpreter_lock) + PyThread_release_lock(interpreter_lock); +#endif + return tstate; +} + +void +PyEval_RestoreThread(tstate) + PyThreadState *tstate; +{ + if (tstate == NULL) + Py_FatalError("PyEval_RestoreThread: NULL tstate"); +#ifdef WITH_THREAD + if (interpreter_lock) { + int err = errno; + PyThread_acquire_lock(interpreter_lock, 1); + errno = err; + } +#endif + PyThreadState_Swap(tstate); +} + + +/* Mechanism whereby asynchronously executing callbacks (e.g. UNIX + signal handlers or Mac I/O completion routines) can schedule calls + to a function to be called synchronously. + The synchronous function is called with one void* argument. + It should return 0 for success or -1 for failure -- failure should + be accompanied by an exception. + + If registry succeeds, the registry function returns 0; if it fails + (e.g. due to too many pending calls) it returns -1 (without setting + an exception condition). + + Note that because registry may occur from within signal handlers, + or other asynchronous events, calling malloc() is unsafe! + +#ifdef WITH_THREAD + Any thread can schedule pending calls, but only the main thread + will execute them. +#endif + + XXX WARNING! ASYNCHRONOUSLY EXECUTING CODE! + There are two possible race conditions: + (1) nested asynchronous registry calls; + (2) registry calls made while pending calls are being processed. + While (1) is very unlikely, (2) is a real possibility. + The current code is safe against (2), but not against (1). + The safety against (2) is derived from the fact that only one + thread (the main thread) ever takes things out of the queue. + + XXX Darn! With the advent of thread state, we should have an array + of pending calls per thread in the thread state! Later... +*/ + +#define NPENDINGCALLS 32 +static struct { + int (*func) Py_PROTO((ANY *)); + ANY *arg; +} pendingcalls[NPENDINGCALLS]; +static volatile int pendingfirst = 0; +static volatile int pendinglast = 0; +static volatile int things_to_do = 0; + +int +Py_AddPendingCall(func, arg) + int (*func) Py_PROTO((ANY *)); + ANY *arg; +{ + static int busy = 0; + int i, j; + /* XXX Begin critical section */ + /* XXX If you want this to be safe against nested + XXX asynchronous calls, you'll have to work harder! */ + if (busy) + return -1; + busy = 1; + i = pendinglast; + j = (i + 1) % NPENDINGCALLS; + if (j == pendingfirst) + return -1; /* Queue full */ + pendingcalls[i].func = func; + pendingcalls[i].arg = arg; + pendinglast = j; + things_to_do = 1; /* Signal main loop */ + busy = 0; + /* XXX End critical section */ + return 0; +} + +int +Py_MakePendingCalls() +{ + static int busy = 0; +#ifdef WITH_THREAD + if (main_thread && PyThread_get_thread_ident() != main_thread) + return 0; +#endif + if (busy) + return 0; + busy = 1; + things_to_do = 0; + for (;;) { + int i; + int (*func) Py_PROTO((ANY *)); + ANY *arg; + i = pendingfirst; + if (i == pendinglast) + break; /* Queue empty */ + func = pendingcalls[i].func; + arg = pendingcalls[i].arg; + pendingfirst = (i + 1) % NPENDINGCALLS; + if (func(arg) < 0) { + busy = 0; + things_to_do = 1; /* We're not done yet */ + return -1; + } + } + busy = 0; + return 0; +} + + +/* Status code for main loop (reason for stack unwind) */ + +enum why_code { + WHY_NOT, /* No error */ + WHY_EXCEPTION, /* Exception occurred */ + WHY_RERAISE, /* Exception re-raised by 'finally' */ + WHY_RETURN, /* 'return' statement */ + WHY_BREAK /* 'break' statement */ +}; + +static enum why_code do_raise Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int unpack_sequence Py_PROTO((PyObject *, int, PyObject **)); + + +/* Backward compatible interface */ + +PyObject * +PyEval_EvalCode(co, globals, locals) + PyCodeObject *co; + PyObject *globals; + PyObject *locals; +{ + return eval_code2(co, + globals, locals, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + (PyObject *)NULL); +} + + +/* Interpreter main loop */ + +#ifndef MAX_RECURSION_DEPTH +#define MAX_RECURSION_DEPTH 10000 +#endif + +static PyObject * +eval_code2(co, globals, locals, + args, argcount, kws, kwcount, defs, defcount, owner) + PyCodeObject *co; + PyObject *globals; + PyObject *locals; + PyObject **args; + int argcount; + PyObject **kws; /* length: 2*kwcount */ + int kwcount; + PyObject **defs; + int defcount; + PyObject *owner; +{ +#ifdef DXPAIRS + int lastopcode = 0; +#endif + register unsigned char *next_instr; + register int opcode; /* Current opcode */ + register int oparg; /* Current opcode argument, if any */ + register PyObject **stack_pointer; + register enum why_code why; /* Reason for block stack unwind */ + register int err; /* Error status -- nonzero if error */ + register PyObject *x; /* Result object -- NULL if error */ + register PyObject *v; /* Temporary objects popped off stack */ + register PyObject *w; + register PyObject *u; + register PyObject *t; + register PyFrameObject *f; /* Current frame */ + register PyObject **fastlocals; + PyObject *retval = NULL; /* Return value */ + PyThreadState *tstate = PyThreadState_GET(); + unsigned char *first_instr; +#ifdef LLTRACE + int lltrace; +#endif +#if defined(Py_DEBUG) || defined(LLTRACE) + /* Make it easier to find out where we are with a debugger */ + char *filename = PyString_AsString(co->co_filename); +#endif + +/* Code access macros */ + +#define GETCONST(i) Getconst(f, i) +#define GETNAME(i) Getname(f, i) +#define GETNAMEV(i) Getnamev(f, i) +#define INSTR_OFFSET() (next_instr - first_instr) +#define NEXTOP() (*next_instr++) +#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) +#define JUMPTO(x) (next_instr = first_instr + (x)) +#define JUMPBY(x) (next_instr += (x)) + +/* Stack manipulation macros */ + +#define STACK_LEVEL() (stack_pointer - f->f_valuestack) +#define EMPTY() (STACK_LEVEL() == 0) +#define TOP() (stack_pointer[-1]) +#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +#define BASIC_POP() (*--stack_pointer) + +#ifdef LLTRACE +#define PUSH(v) (BASIC_PUSH(v), lltrace && prtrace(TOP(), "push")) +#define POP() (lltrace && prtrace(TOP(), "pop"), BASIC_POP()) +#else +#define PUSH(v) BASIC_PUSH(v) +#define POP() BASIC_POP() +#endif + +/* Local variable macros */ + +#define GETLOCAL(i) (fastlocals[i]) +#define SETLOCAL(i, value) do { Py_XDECREF(GETLOCAL(i)); \ + GETLOCAL(i) = value; } while (0) + +/* Start of code */ + +#ifdef USE_STACKCHECK + if (tstate->recursion_depth%10 == 0 && PyOS_CheckStack()) { + PyErr_SetString(PyExc_MemoryError, "Stack overflow"); + return NULL; + } +#endif + + if (globals == NULL) { + PyErr_SetString(PyExc_SystemError, "eval_code2: NULL globals"); + return NULL; + } + +#ifdef LLTRACE + lltrace = PyDict_GetItemString(globals, "__lltrace__") != NULL; +#endif + + f = PyFrame_New( + tstate, /*back*/ + co, /*code*/ + globals, /*globals*/ + locals); /*locals*/ + if (f == NULL) + return NULL; + + tstate->frame = f; + fastlocals = f->f_localsplus; + + if (co->co_argcount > 0 || + co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { + int i; + int n = argcount; + PyObject *kwdict = NULL; + if (co->co_flags & CO_VARKEYWORDS) { + kwdict = PyDict_New(); + if (kwdict == NULL) + goto fail; + i = co->co_argcount; + if (co->co_flags & CO_VARARGS) + i++; + SETLOCAL(i, kwdict); + } + if (argcount > co->co_argcount) { + if (!(co->co_flags & CO_VARARGS)) { + PyErr_Format(PyExc_TypeError, + "too many arguments; expected %d, got %d", + co->co_argcount, argcount); + goto fail; + } + n = co->co_argcount; + } + for (i = 0; i < n; i++) { + x = args[i]; + Py_INCREF(x); + SETLOCAL(i, x); + } + if (co->co_flags & CO_VARARGS) { + u = PyTuple_New(argcount - n); + if (u == NULL) + goto fail; + SETLOCAL(co->co_argcount, u); + for (i = n; i < argcount; i++) { + x = args[i]; + Py_INCREF(x); + PyTuple_SET_ITEM(u, i-n, x); + } + } + for (i = 0; i < kwcount; i++) { + PyObject *keyword = kws[2*i]; + PyObject *value = kws[2*i + 1]; + int j; + /* XXX slow -- speed up using dictionary? */ + for (j = 0; j < co->co_argcount; j++) { + PyObject *nm = PyTuple_GET_ITEM( + co->co_varnames, j); + if (PyObject_Compare(keyword, nm) == 0) + break; + } + /* Check errors from Compare */ + if (PyErr_Occurred()) + goto fail; + if (j >= co->co_argcount) { + if (kwdict == NULL) { + PyErr_Format(PyExc_TypeError, + "unexpected keyword argument: %.400s", + PyString_AsString(keyword)); + goto fail; + } + PyDict_SetItem(kwdict, keyword, value); + } + else { + if (GETLOCAL(j) != NULL) { + PyErr_SetString(PyExc_TypeError, + "keyword parameter redefined"); + goto fail; + } + Py_INCREF(value); + SETLOCAL(j, value); + } + } + if (argcount < co->co_argcount) { + int m = co->co_argcount - defcount; + for (i = argcount; i < m; i++) { + if (GETLOCAL(i) == NULL) { + PyErr_Format(PyExc_TypeError, + "not enough arguments; expected %d, got %d", + m, i); + goto fail; + } + } + if (n > m) + i = n - m; + else + i = 0; + for (; i < defcount; i++) { + if (GETLOCAL(m+i) == NULL) { + PyObject *def = defs[i]; + Py_INCREF(def); + SETLOCAL(m+i, def); + } + } + } + } + else { + if (argcount > 0 || kwcount > 0) { + PyErr_SetString(PyExc_TypeError, + "no arguments expected"); + goto fail; + } + } + + if (tstate->sys_tracefunc != NULL) { + /* tstate->sys_tracefunc, if defined, is a function that + will be called on *every* entry to a code block. + Its return value, if not None, is a function that + will be called at the start of each executed line + of code. (Actually, the function must return + itself in order to continue tracing.) + The trace functions are called with three arguments: + a pointer to the current frame, a string indicating + why the function is called, and an argument which + depends on the situation. The global trace function + (sys.trace) is also called whenever an exception + is detected. */ + if (call_trace(&tstate->sys_tracefunc, + &f->f_trace, f, "call", + Py_None/*XXX how to compute arguments now?*/)) { + /* Trace function raised an error */ + goto fail; + } + } + + if (tstate->sys_profilefunc != NULL) { + /* Similar for sys_profilefunc, except it needn't return + itself and isn't called for "line" events */ + if (call_trace(&tstate->sys_profilefunc, + (PyObject**)0, f, "call", + Py_None/*XXX*/)) { + goto fail; + } + } + + if (++tstate->recursion_depth > MAX_RECURSION_DEPTH) { + --tstate->recursion_depth; + PyErr_SetString(PyExc_RuntimeError, + "Maximum recursion depth exceeded"); + tstate->frame = f->f_back; + Py_DECREF(f); + return NULL; + } + + _PyCode_GETCODEPTR(co, &first_instr); + next_instr = first_instr; + stack_pointer = f->f_valuestack; + + why = WHY_NOT; + err = 0; + x = Py_None; /* Not a reference, just anything non-NULL */ + + for (;;) { + /* Do periodic things. Doing this every time through + the loop would add too much overhead, so we do it + only every Nth instruction. We also do it if + ``things_to_do'' is set, i.e. when an asynchronous + event needs attention (e.g. a signal handler or + async I/O handler); see Py_AddPendingCall() and + Py_MakePendingCalls() above. */ + + if (things_to_do || --tstate->ticker < 0) { + tstate->ticker = tstate->interp->checkinterval; + if (things_to_do) { + if (Py_MakePendingCalls() < 0) { + why = WHY_EXCEPTION; + goto on_error; + } + } +#if !defined(HAVE_SIGNAL_H) || defined(macintosh) + /* If we have true signals, the signal handler + will call Py_AddPendingCall() so we don't + have to call sigcheck(). On the Mac and + DOS, alas, we have to call it. */ + if (PyErr_CheckSignals()) { + why = WHY_EXCEPTION; + goto on_error; + } +#endif + +#ifdef WITH_THREAD + if (interpreter_lock) { + /* Give another thread a chance */ + + if (PyThreadState_Swap(NULL) != tstate) + Py_FatalError("ceval: tstate mix-up"); + PyThread_release_lock(interpreter_lock); + + /* Other threads may run now */ + + PyThread_acquire_lock(interpreter_lock, 1); + if (PyThreadState_Swap(tstate) != NULL) + Py_FatalError("ceval: orphan tstate"); + } +#endif + } + + /* Extract opcode and argument */ + +#if defined(Py_DEBUG) || defined(LLTRACE) + f->f_lasti = INSTR_OFFSET(); +#endif + + opcode = NEXTOP(); + if (HAS_ARG(opcode)) + oparg = NEXTARG(); +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS + dxpairs[lastopcode][opcode]++; + lastopcode = opcode; +#endif + dxp[opcode]++; +#endif + +#ifdef LLTRACE + /* Instruction tracing */ + + if (lltrace) { + if (HAS_ARG(opcode)) { + printf("%d: %d, %d\n", + (int) (INSTR_OFFSET() - 3), + opcode, oparg); + } + else { + printf("%d: %d\n", + (int) (INSTR_OFFSET() - 1), opcode); + } + } +#endif + + /* Main switch on opcode */ + + switch (opcode) { + + /* BEWARE! + It is essential that any operation that fails sets either + x to NULL, err to nonzero, or why to anything but WHY_NOT, + and that no operation that succeeds does this! */ + + /* case STOP_CODE: this is an error! */ + + case POP_TOP: + v = POP(); + Py_DECREF(v); + continue; + + case ROT_TWO: + v = POP(); + w = POP(); + PUSH(v); + PUSH(w); + continue; + + case ROT_THREE: + v = POP(); + w = POP(); + x = POP(); + PUSH(v); + PUSH(x); + PUSH(w); + continue; + + case DUP_TOP: + v = TOP(); + Py_INCREF(v); + PUSH(v); + continue; + + case UNARY_POSITIVE: + v = POP(); + x = PyNumber_Positive(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_NEGATIVE: + v = POP(); + x = PyNumber_Negative(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_NOT: + v = POP(); + err = PyObject_IsTrue(v); + Py_DECREF(v); + if (err == 0) { + Py_INCREF(Py_True); + PUSH(Py_True); + continue; + } + else if (err > 0) { + Py_INCREF(Py_False); + PUSH(Py_False); + err = 0; + continue; + } + break; + + case UNARY_CONVERT: + v = POP(); + x = PyObject_Repr(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case UNARY_INVERT: + v = POP(); + x = PyNumber_Invert(v); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_POWER: + w = POP(); + v = POP(); + x = PyNumber_Power(v, w, Py_None); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_MULTIPLY: + w = POP(); + v = POP(); + x = PyNumber_Multiply(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_DIVIDE: + w = POP(); + v = POP(); + x = PyNumber_Divide(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_MODULO: + w = POP(); + v = POP(); + x = PyNumber_Remainder(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_ADD: + w = POP(); + v = POP(); + if (PyInt_Check(v) && PyInt_Check(w)) { + /* INLINE: int + int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a + b; + if ((i^a) < 0 && (i^b) < 0) { + PyErr_SetString(PyExc_OverflowError, + "integer addition"); + x = NULL; + } + else + x = PyInt_FromLong(i); + } + else + x = PyNumber_Add(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_SUBTRACT: + w = POP(); + v = POP(); + if (PyInt_Check(v) && PyInt_Check(w)) { + /* INLINE: int - int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a - b; + if ((i^a) < 0 && (i^~b) < 0) { + PyErr_SetString(PyExc_OverflowError, + "integer subtraction"); + x = NULL; + } + else + x = PyInt_FromLong(i); + } + else + x = PyNumber_Subtract(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_SUBSCR: + w = POP(); + v = POP(); + if (PyList_Check(v) && PyInt_Check(w)) { + /* INLINE: list[int] */ + long i = PyInt_AsLong(w); + if (i < 0) + i += PyList_GET_SIZE(v); + if (i < 0 || + i >= PyList_GET_SIZE(v)) { + PyErr_SetString(PyExc_IndexError, + "list index out of range"); + x = NULL; + } + else { + x = PyList_GET_ITEM(v, i); + Py_INCREF(x); + } + } + else + x = PyObject_GetItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_LSHIFT: + w = POP(); + v = POP(); + x = PyNumber_Lshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_RSHIFT: + w = POP(); + v = POP(); + x = PyNumber_Rshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_AND: + w = POP(); + v = POP(); + x = PyNumber_And(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_XOR: + w = POP(); + v = POP(); + x = PyNumber_Xor(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case BINARY_OR: + w = POP(); + v = POP(); + x = PyNumber_Or(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case SLICE+0: + case SLICE+1: + case SLICE+2: + case SLICE+3: + if ((opcode-SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + x = apply_slice(u, v, w); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case STORE_SLICE+0: + case STORE_SLICE+1: + case STORE_SLICE+2: + case STORE_SLICE+3: + if ((opcode-STORE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-STORE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + t = POP(); + err = assign_slice(u, v, w, t); /* u[v:w] = t */ + Py_DECREF(t); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case DELETE_SLICE+0: + case DELETE_SLICE+1: + case DELETE_SLICE+2: + case DELETE_SLICE+3: + if ((opcode-DELETE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-DELETE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + err = assign_slice(u, v, w, (PyObject *)NULL); + /* del u[v:w] */ + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case STORE_SUBSCR: + w = POP(); + v = POP(); + u = POP(); + /* v[w] = u */ + err = PyObject_SetItem(v, w, u); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case DELETE_SUBSCR: + w = POP(); + v = POP(); + /* del v[w] */ + err = PyObject_DelItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case PRINT_EXPR: + v = POP(); + /* Print value except if None */ + /* After printing, also assign to '_' */ + /* Before, set '_' to None to avoid recursion */ + if (v != Py_None && + (err = PyDict_SetItemString( + f->f_builtins, "_", Py_None)) == 0) { + err = Py_FlushLine(); + if (err == 0) { + x = PySys_GetObject("stdout"); + if (x == NULL) { + PyErr_SetString( + PyExc_RuntimeError, + "lost sys.stdout"); + err = -1; + } + } + if (err == 0) + err = PyFile_WriteObject(v, x, 0); + if (err == 0) { + PyFile_SoftSpace(x, 1); + err = Py_FlushLine(); + } + if (err == 0) { + err = PyDict_SetItemString( + f->f_builtins, "_", v); + } + } + Py_DECREF(v); + break; + + case PRINT_ITEM: + v = POP(); + w = PySys_GetObject("stdout"); + if (w == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "lost sys.stdout"); + err = -1; + } + else if (PyFile_SoftSpace(w, 1)) + err = PyFile_WriteString(" ", w); + if (err == 0) + err = PyFile_WriteObject(v, w, Py_PRINT_RAW); + if (err == 0 && PyString_Check(v)) { + /* XXX move into writeobject() ? */ + char *s = PyString_AsString(v); + int len = PyString_Size(v); + if (len > 0 && + isspace(Py_CHARMASK(s[len-1])) && + s[len-1] != ' ') + PyFile_SoftSpace(w, 0); + } + Py_DECREF(v); + if (err == 0) continue; + break; + + case PRINT_NEWLINE: + x = PySys_GetObject("stdout"); + if (x == NULL) + PyErr_SetString(PyExc_RuntimeError, + "lost sys.stdout"); + else { + err = PyFile_WriteString("\n", x); + if (err == 0) + PyFile_SoftSpace(x, 0); + } + break; + + case BREAK_LOOP: + why = WHY_BREAK; + break; + + case RAISE_VARARGS: + u = v = w = NULL; + switch (oparg) { + case 3: + u = POP(); /* traceback */ + /* Fallthrough */ + case 2: + v = POP(); /* value */ + /* Fallthrough */ + case 1: + w = POP(); /* exc */ + case 0: /* Fallthrough */ + why = do_raise(w, v, u); + break; + default: + PyErr_SetString(PyExc_SystemError, + "bad RAISE_VARARGS oparg"); + why = WHY_EXCEPTION; + break; + } + break; + + case LOAD_LOCALS: + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + Py_INCREF(x); + PUSH(x); + break; + + case RETURN_VALUE: + retval = POP(); + why = WHY_RETURN; + break; + + case EXEC_STMT: + w = POP(); + v = POP(); + u = POP(); + err = exec_statement(f, u, v, w); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case POP_BLOCK: + { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_DECREF(v); + } + } + break; + + case END_FINALLY: + v = POP(); + if (PyInt_Check(v)) { + why = (enum why_code) PyInt_AsLong(v); + if (why == WHY_RETURN) + retval = POP(); + } + else if (PyString_Check(v) || PyClass_Check(v)) { + w = POP(); + u = POP(); + PyErr_Restore(v, w, u); + why = WHY_RERAISE; + break; + } + else if (v != Py_None) { + PyErr_SetString(PyExc_SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; + } + Py_DECREF(v); + break; + + case BUILD_CLASS: + u = POP(); + v = POP(); + w = POP(); + x = build_class(u, v, w); + PUSH(x); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case STORE_NAME: + w = GETNAMEV(oparg); + v = POP(); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + err = PyDict_SetItem(x, w, v); + Py_DECREF(v); + break; + + case DELETE_NAME: + w = GETNAMEV(oparg); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + if ((err = PyDict_DelItem(x, w)) != 0) + PyErr_SetObject(PyExc_NameError, w); + break; + +#ifdef CASE_TOO_BIG + default: switch (opcode) { +#endif + + case UNPACK_TUPLE: + case UNPACK_LIST: + v = POP(); + if (PyTuple_Check(v)) { + if (PyTuple_Size(v) != oparg) { + PyErr_SetString(PyExc_ValueError, + "unpack tuple of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = PyTuple_GET_ITEM(v, oparg); + Py_INCREF(w); + PUSH(w); + } + } + } + else if (PyList_Check(v)) { + if (PyList_Size(v) != oparg) { + PyErr_SetString(PyExc_ValueError, + "unpack list of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = PyList_GET_ITEM(v, oparg); + Py_INCREF(w); + PUSH(w); + } + } + } + else if (PySequence_Check(v)) { + if (unpack_sequence(v, oparg, + stack_pointer + oparg)) + stack_pointer += oparg; + else + why = WHY_EXCEPTION; + } + else { + PyErr_SetString(PyExc_TypeError, + "unpack non-sequence"); + why = WHY_EXCEPTION; + } + Py_DECREF(v); + break; + + case STORE_ATTR: + w = GETNAMEV(oparg); + v = POP(); + u = POP(); + err = PyObject_SetAttr(v, w, u); /* v.w = u */ + Py_DECREF(v); + Py_DECREF(u); + break; + + case DELETE_ATTR: + w = GETNAMEV(oparg); + v = POP(); + err = PyObject_SetAttr(v, w, (PyObject *)NULL); + /* del v.w */ + Py_DECREF(v); + break; + + case STORE_GLOBAL: + w = GETNAMEV(oparg); + v = POP(); + err = PyDict_SetItem(f->f_globals, w, v); + Py_DECREF(v); + break; + + case DELETE_GLOBAL: + w = GETNAMEV(oparg); + if ((err = PyDict_DelItem(f->f_globals, w)) != 0) + PyErr_SetObject(PyExc_NameError, w); + break; + + case LOAD_CONST: + x = GETCONST(oparg); + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_NAME: + w = GETNAMEV(oparg); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + x = PyDict_GetItem(x, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + PyErr_SetObject( + PyExc_NameError, w); + break; + } + } + } + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_GLOBAL: + w = GETNAMEV(oparg); + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + PyErr_SetObject(PyExc_NameError, w); + break; + } + } + Py_INCREF(x); + PUSH(x); + break; + + case LOAD_FAST: + x = GETLOCAL(oparg); + if (x == NULL) { + PyErr_SetObject(PyExc_UnboundLocalError, + PyTuple_GetItem(co->co_varnames, + oparg)); + break; + } + Py_INCREF(x); + PUSH(x); + if (x != NULL) continue; + break; + + case STORE_FAST: + v = POP(); + SETLOCAL(oparg, v); + continue; + + case DELETE_FAST: + x = GETLOCAL(oparg); + if (x == NULL) { + PyErr_SetObject(PyExc_UnboundLocalError, + PyTuple_GetItem(co->co_varnames, + oparg)); + break; + } + SETLOCAL(oparg, NULL); + continue; + + case BUILD_TUPLE: + x = PyTuple_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + PyTuple_SET_ITEM(x, oparg, w); + } + PUSH(x); + continue; + } + break; + + case BUILD_LIST: + x = PyList_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + PyList_SET_ITEM(x, oparg, w); + } + PUSH(x); + continue; + } + break; + + case BUILD_MAP: + x = PyDict_New(); + PUSH(x); + if (x != NULL) continue; + break; + + case LOAD_ATTR: + w = GETNAMEV(oparg); + v = POP(); + x = PyObject_GetAttr(v, w); + Py_DECREF(v); + PUSH(x); + if (x != NULL) continue; + break; + + case COMPARE_OP: + w = POP(); + v = POP(); + if (PyInt_Check(v) && PyInt_Check(w)) { + /* INLINE: cmp(int, int) */ + register long a, b; + register int res; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + switch (oparg) { + case LT: res = a < b; break; + case LE: res = a <= b; break; + case EQ: res = a == b; break; + case NE: res = a != b; break; + case GT: res = a > b; break; + case GE: res = a >= b; break; + case IS: res = v == w; break; + case IS_NOT: res = v != w; break; + default: goto slow_compare; + } + x = res ? Py_True : Py_False; + Py_INCREF(x); + } + else { + slow_compare: + x = cmp_outcome(oparg, v, w); + } + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case IMPORT_NAME: + w = GETNAMEV(oparg); + x = PyDict_GetItemString(f->f_builtins, "__import__"); + if (x == NULL) { + PyErr_SetString(PyExc_ImportError, + "__import__ not found"); + break; + } + u = find_from_args(f, INSTR_OFFSET()); + if (u == NULL) { + x = u; + break; + } + w = Py_BuildValue("(OOOO)", + w, + f->f_globals, + f->f_locals == NULL ? + Py_None : f->f_locals, + u); + Py_DECREF(u); + if (w == NULL) { + x = NULL; + break; + } + x = PyEval_CallObject(x, w); + Py_DECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + case IMPORT_FROM: + w = GETNAMEV(oparg); + v = TOP(); + PyFrame_FastToLocals(f); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals"); + break; + } + err = import_from(x, v, w); + PyFrame_LocalsToFast(f, 0); + if (err == 0) continue; + break; + + case JUMP_FORWARD: + JUMPBY(oparg); + continue; + + case JUMP_IF_FALSE: + err = PyObject_IsTrue(TOP()); + if (err > 0) + err = 0; + else if (err == 0) + JUMPBY(oparg); + else + break; + continue; + + case JUMP_IF_TRUE: + err = PyObject_IsTrue(TOP()); + if (err > 0) { + err = 0; + JUMPBY(oparg); + } + else if (err == 0) + ; + else + break; + continue; + + case JUMP_ABSOLUTE: + JUMPTO(oparg); + continue; + + case FOR_LOOP: + /* for v in s: ... + On entry: stack contains s, i. + On exit: stack contains s, i+1, s[i]; + but if loop exhausted: + s, i are popped, and we jump */ + w = POP(); /* Loop index */ + v = POP(); /* Sequence object */ + u = loop_subscript(v, w); + if (u != NULL) { + PUSH(v); + x = PyInt_FromLong(PyInt_AsLong(w)+1); + PUSH(x); + Py_DECREF(w); + PUSH(u); + if (x != NULL) continue; + } + else { + Py_DECREF(v); + Py_DECREF(w); + /* A NULL can mean "s exhausted" + but also an error: */ + if (PyErr_Occurred()) + why = WHY_EXCEPTION; + else { + JUMPBY(oparg); + continue; + } + } + break; + + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); + continue; + + case SET_LINENO: +#ifdef LLTRACE + if (lltrace) + printf("--- %s:%d \n", filename, oparg); +#endif + f->f_lineno = oparg; + if (f->f_trace == NULL) + continue; + /* Trace each line of code reached */ + f->f_lasti = INSTR_OFFSET(); + err = call_trace(&f->f_trace, &f->f_trace, + f, "line", Py_None); + break; + + case CALL_FUNCTION: + { + int na = oparg & 0xff; + int nk = (oparg>>8) & 0xff; + int n = na + 2*nk; + PyObject **pfunc = stack_pointer - n - 1; + PyObject *func = *pfunc; + PyObject *self = NULL; + PyObject *class = NULL; + f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */ + if (PyMethod_Check(func)) { + self = PyMethod_Self(func); + class = PyMethod_Class(func); + func = PyMethod_Function(func); + Py_INCREF(func); + if (self != NULL) { + Py_INCREF(self); + Py_DECREF(*pfunc); + *pfunc = self; + na++; + n++; + } + else { + /* Unbound methods must be + called with an instance of + the class (or a derived + class) as first argument */ + if (na > 0 && + (self = stack_pointer[-n]) + != NULL && + PyInstance_Check(self) && + PyClass_IsSubclass( + (PyObject *) + (((PyInstanceObject *)self) + ->in_class), + class)) + /* Handy-dandy */ ; + else { + PyErr_SetString( + PyExc_TypeError, + "unbound method must be called with class instance 1st argument"); + x = NULL; + break; + } + } + } + else + Py_INCREF(func); + if (PyFunction_Check(func)) { + PyObject *co = PyFunction_GetCode(func); + PyObject *globals = + PyFunction_GetGlobals(func); + PyObject *argdefs = + PyFunction_GetDefaults(func); + PyObject **d; + int nd; + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = ((PyTupleObject *)argdefs) -> + ob_size; + } + else { + d = NULL; + nd = 0; + } + x = eval_code2( + (PyCodeObject *)co, + globals, (PyObject *)NULL, + stack_pointer-n, na, + stack_pointer-2*nk, nk, + d, nd, + class); + } + else { + PyObject *args = PyTuple_New(na); + PyObject *kwdict = NULL; + if (args == NULL) { + x = NULL; + break; + } + if (nk > 0) { + kwdict = PyDict_New(); + if (kwdict == NULL) { + x = NULL; + break; + } + err = 0; + while (--nk >= 0) { + PyObject *value = POP(); + PyObject *key = POP(); + err = PyDict_SetItem( + kwdict, key, value); + Py_DECREF(key); + Py_DECREF(value); + if (err) + break; + } + if (err) { + Py_DECREF(args); + Py_DECREF(kwdict); + break; + } + } + while (--na >= 0) { + w = POP(); + PyTuple_SET_ITEM(args, na, w); + } + x = PyEval_CallObjectWithKeywords( + func, args, kwdict); + Py_DECREF(args); + Py_XDECREF(kwdict); + } + Py_DECREF(func); + while (stack_pointer > pfunc) { + w = POP(); + Py_DECREF(w); + } + PUSH(x); + if (x != NULL) continue; + break; + } + + case MAKE_FUNCTION: + v = POP(); /* code object */ + x = PyFunction_New(v, f->f_globals); + Py_DECREF(v); + /* XXX Maybe this should be a separate opcode? */ + if (x != NULL && oparg > 0) { + v = PyTuple_New(oparg); + if (v == NULL) { + Py_DECREF(x); + x = NULL; + break; + } + while (--oparg >= 0) { + w = POP(); + PyTuple_SET_ITEM(v, oparg, w); + } + err = PyFunction_SetDefaults(x, v); + Py_DECREF(v); + } + PUSH(x); + break; + + case BUILD_SLICE: + if (oparg == 3) + w = POP(); + else + w = NULL; + v = POP(); + u = POP(); + x = PySlice_New(u, v, w); + Py_DECREF(u); + Py_DECREF(v); + Py_XDECREF(w); + PUSH(x); + if (x != NULL) continue; + break; + + + default: + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + f->f_lineno, opcode); + PyErr_SetString(PyExc_SystemError, "unknown opcode"); + why = WHY_EXCEPTION; + break; + +#ifdef CASE_TOO_BIG + } +#endif + + } /* switch */ + + on_error: + + /* Quickly continue if no error occurred */ + + if (why == WHY_NOT) { + if (err == 0 && x != NULL) { +#ifdef CHECKEXC + /* This check is expensive! */ + if (PyErr_Occurred()) + fprintf(stderr, + "XXX undetected error\n"); + else +#endif + continue; /* Normal, fast path */ + } + why = WHY_EXCEPTION; + x = Py_None; + err = 0; + } + + /* Double-check exception status */ + + if (why == WHY_EXCEPTION || why == WHY_RERAISE) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_SystemError, + "error return without exception set"); + why = WHY_EXCEPTION; + } + } +#ifdef CHECKEXC + else { + /* This check is expensive! */ + if (PyErr_Occurred()) { + fprintf(stderr, + "XXX undetected error (why=%d)\n", + why); + why = WHY_EXCEPTION; + } + } +#endif + + /* Log traceback info if this is a real exception */ + + if (why == WHY_EXCEPTION) { + f->f_lasti = INSTR_OFFSET() - 1; + if (HAS_ARG(opcode)) + f->f_lasti -= 2; + PyTraceBack_Here(f); + + if (f->f_trace) + call_exc_trace(&f->f_trace, &f->f_trace, f); + if (tstate->sys_profilefunc) + call_exc_trace(&tstate->sys_profilefunc, + (PyObject**)0, f); + } + + /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ + + if (why == WHY_RERAISE) + why = WHY_EXCEPTION; + + /* Unwind stacks if a (pseudo) exception occurred */ + + while (why != WHY_NOT && f->f_iblock > 0) { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_XDECREF(v); + } + if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + if (b->b_type == SETUP_FINALLY || + (b->b_type == SETUP_EXCEPT && + why == WHY_EXCEPTION)) { + if (why == WHY_EXCEPTION) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (val == NULL) { + val = Py_None; + Py_INCREF(val); + } + /* Make the raw exception data + available to the handler, + so a program can emulate the + Python main loop. Don't do + this for 'finally'. */ + if (b->b_type == SETUP_EXCEPT) { + PyErr_NormalizeException( + &exc, &val, &tb); + set_exc_info(tstate, + exc, val, tb); + } + PUSH(tb); + PUSH(val); + PUSH(exc); + } + else { + if (why == WHY_RETURN) + PUSH(retval); + v = PyInt_FromLong((long)why); + PUSH(v); + } + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + } /* unwind stack */ + + /* End the loop if we still have an error (or return) */ + + if (why != WHY_NOT) + break; + + } /* main loop */ + + /* Pop remaining stack entries */ + + while (!EMPTY()) { + v = POP(); + Py_XDECREF(v); + } + + if (why != WHY_RETURN) + retval = NULL; + + if (f->f_trace) { + if (why == WHY_RETURN) { + if (call_trace(&f->f_trace, &f->f_trace, f, + "return", retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + } + + if (tstate->sys_profilefunc && why == WHY_RETURN) { + if (call_trace(&tstate->sys_profilefunc, (PyObject**)0, + f, "return", retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + + reset_exc_info(tstate); + + --tstate->recursion_depth; + + fail: /* Jump here from prelude on failure */ + + /* Restore previous frame and release the current one */ + + tstate->frame = f->f_back; + Py_DECREF(f); + + return retval; +} + +static void +set_exc_info(tstate, type, value, tb) + PyThreadState *tstate; + PyObject *type; + PyObject *value; + PyObject *tb; +{ + PyFrameObject *frame; + PyObject *tmp_type, *tmp_value, *tmp_tb; + + frame = tstate->frame; + if (frame->f_exc_type == NULL) { + /* This frame didn't catch an exception before */ + /* Save previous exception of this thread in this frame */ + if (tstate->exc_type == NULL) { + Py_INCREF(Py_None); + tstate->exc_type = Py_None; + } + tmp_type = frame->f_exc_type; + tmp_value = frame->f_exc_value; + tmp_tb = frame->f_exc_traceback; + Py_XINCREF(tstate->exc_type); + Py_XINCREF(tstate->exc_value); + Py_XINCREF(tstate->exc_traceback); + frame->f_exc_type = tstate->exc_type; + frame->f_exc_value = tstate->exc_value; + frame->f_exc_traceback = tstate->exc_traceback; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + } + /* Set new exception for this thread */ + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + Py_XINCREF(type); + Py_XINCREF(value); + Py_XINCREF(tb); + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + /* For b/w compatibility */ + PySys_SetObject("exc_type", type); + PySys_SetObject("exc_value", value); + PySys_SetObject("exc_traceback", tb); +} + +static void +reset_exc_info(tstate) + PyThreadState *tstate; +{ + PyFrameObject *frame; + PyObject *tmp_type, *tmp_value, *tmp_tb; + frame = tstate->frame; + if (frame->f_exc_type != NULL) { + /* This frame caught an exception */ + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + Py_XINCREF(frame->f_exc_type); + Py_XINCREF(frame->f_exc_value); + Py_XINCREF(frame->f_exc_traceback); + tstate->exc_type = frame->f_exc_type; + tstate->exc_value = frame->f_exc_value; + tstate->exc_traceback = frame->f_exc_traceback; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + /* For b/w compatibility */ + PySys_SetObject("exc_type", frame->f_exc_type); + PySys_SetObject("exc_value", frame->f_exc_value); + PySys_SetObject("exc_traceback", frame->f_exc_traceback); + } + tmp_type = frame->f_exc_type; + tmp_value = frame->f_exc_value; + tmp_tb = frame->f_exc_traceback; + frame->f_exc_type = NULL; + frame->f_exc_value = NULL; + frame->f_exc_traceback = NULL; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} + +/* Logic for the raise statement (too complicated for inlining). + This *consumes* a reference count to each of its arguments. */ +static enum why_code +do_raise(type, value, tb) + PyObject *type, *value, *tb; +{ + if (type == NULL) { + /* Reraise */ + PyThreadState *tstate = PyThreadState_Get(); + type = tstate->exc_type == NULL ? Py_None : tstate->exc_type; + value = tstate->exc_value; + tb = tstate->exc_traceback; + Py_XINCREF(type); + Py_XINCREF(value); + Py_XINCREF(tb); + } + + /* We support the following forms of raise: + raise , + raise , + raise , None + raise , + raise , None + raise , + raise , None + + An omitted second argument is the same as None. + + In addition, raise , is the same as + raising the tuple's first item (and it better have one!); + this rule is applied recursively. + + Finally, an optional third argument can be supplied, which + gives the traceback to be substituted (useful when + re-raising an exception after examining it). */ + + /* First, check the traceback argument, replacing None with + NULL. */ + if (tb == Py_None) { + Py_DECREF(tb); + tb = NULL; + } + else if (tb != NULL && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise 3rd arg must be traceback or None"); + goto raise_error; + } + + /* Next, replace a missing value with None */ + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + + /* Next, repeatedly, replace a tuple exception with its first item */ + while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { + PyObject *tmp = type; + type = PyTuple_GET_ITEM(type, 0); + Py_INCREF(type); + Py_DECREF(tmp); + } + + if (PyString_Check(type)) + ; + + else if (PyClass_Check(type)) + PyErr_NormalizeException(&type, &value, &tb); + + else if (PyInstance_Check(type)) { + /* Raising an instance. The value should be a dummy. */ + if (value != Py_None) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + else { + /* Normalize to raise , */ + Py_DECREF(value); + value = type; + type = (PyObject*) ((PyInstanceObject*)type)->in_class; + Py_INCREF(type); + } + } + else { + /* Not something you can raise. You get an exception + anyway, just not what you specified :-) */ + PyErr_SetString(PyExc_TypeError, + "exceptions must be strings, classes, or instances"); + goto raise_error; + } + PyErr_Restore(type, value, tb); + if (tb == NULL) + return WHY_EXCEPTION; + else + return WHY_RERAISE; + raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return WHY_EXCEPTION; +} + +static int +unpack_sequence(v, argcnt, sp) + PyObject *v; + int argcnt; + PyObject **sp; +{ + int i; + PyObject *w; + + for (i = 0; i < argcnt; i++) { + if (! (w = PySequence_GetItem(v, i))) { + if (PyErr_ExceptionMatches(PyExc_IndexError)) + PyErr_SetString(PyExc_ValueError, + "unpack sequence of wrong size"); + goto finally; + } + *--sp = w; + } + /* we better get an IndexError now */ + if (PySequence_GetItem(v, i) == NULL) { + if (PyErr_ExceptionMatches(PyExc_IndexError)) { + PyErr_Clear(); + return 1; + } + /* some other exception occurred. fall through to finally */ + } + else + PyErr_SetString(PyExc_ValueError, + "unpack sequence of wrong size"); + /* fall through */ +finally: + for (; i > 0; i--, sp++) + Py_DECREF(*sp); + + return 0; +} + + +#ifdef LLTRACE +static int +prtrace(v, str) + PyObject *v; + char *str; +{ + printf("%s ", str); + if (PyObject_Print(v, stdout, 0) != 0) + PyErr_Clear(); /* Don't know what else to do */ + printf("\n"); +} +#endif + +static void +call_exc_trace(p_trace, p_newtrace, f) + PyObject **p_trace, **p_newtrace; + PyFrameObject *f; +{ + PyObject *type, *value, *traceback, *arg; + int err; + PyErr_Fetch(&type, &value, &traceback); + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + arg = Py_BuildValue("(OOO)", type, value, traceback); + if (arg == NULL) { + PyErr_Restore(type, value, traceback); + return; + } + err = call_trace(p_trace, p_newtrace, f, "exception", arg); + Py_DECREF(arg); + if (err == 0) + PyErr_Restore(type, value, traceback); + else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } +} + +static int +call_trace(p_trace, p_newtrace, f, msg, arg) + PyObject **p_trace; /* in/out; may not be NULL; + may not point to NULL variable initially */ + PyObject **p_newtrace; /* in/out; may be NULL; + may point to NULL variable; + may be same variable as p_newtrace */ + PyFrameObject *f; + char *msg; + PyObject *arg; +{ + PyThreadState *tstate = f->f_tstate; + PyObject *args, *what; + PyObject *res = NULL; + + if (tstate->tracing) { + /* Don't do recursive traces */ + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + *p_newtrace = NULL; + } + return 0; + } + + args = PyTuple_New(3); + if (args == NULL) + goto cleanup; + what = PyString_FromString(msg); + if (what == NULL) + goto cleanup; + Py_INCREF(f); + PyTuple_SET_ITEM(args, 0, (PyObject *)f); + PyTuple_SET_ITEM(args, 1, what); + if (arg == NULL) + arg = Py_None; + Py_INCREF(arg); + PyTuple_SET_ITEM(args, 2, arg); + tstate->tracing++; + PyFrame_FastToLocals(f); + res = PyEval_CallObject(*p_trace, args); /* May clear *p_trace! */ + PyFrame_LocalsToFast(f, 1); + tstate->tracing--; + cleanup: + Py_XDECREF(args); + if (res == NULL) { + /* The trace proc raised an exception */ + PyTraceBack_Here(f); + Py_XDECREF(*p_trace); + *p_trace = NULL; + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + *p_newtrace = NULL; + } + /* to be extra double plus sure we don't get recursive + * calls inf either tracefunc or profilefunc gets an + * exception, zap the global variables. + */ + Py_XDECREF(tstate->sys_tracefunc); + tstate->sys_tracefunc = NULL; + Py_XDECREF(tstate->sys_profilefunc); + tstate->sys_profilefunc = NULL; + return -1; + } + else { + if (p_newtrace) { + Py_XDECREF(*p_newtrace); + if (res == Py_None) + *p_newtrace = NULL; + else { + Py_INCREF(res); + *p_newtrace = res; + } + } + Py_DECREF(res); + return 0; + } +} + +PyObject * +PyEval_GetBuiltins() +{ + PyThreadState *tstate = PyThreadState_Get(); + PyFrameObject *current_frame = tstate->frame; + if (current_frame == NULL) + return tstate->interp->builtins; + else + return current_frame->f_builtins; +} + +PyObject * +PyEval_GetLocals() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + if (current_frame == NULL) + return NULL; + PyFrame_FastToLocals(current_frame); + return current_frame->f_locals; +} + +PyObject * +PyEval_GetGlobals() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + if (current_frame == NULL) + return NULL; + else + return current_frame->f_globals; +} + +PyObject * +PyEval_GetFrame() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + return (PyObject *)current_frame; +} + +int +PyEval_GetRestricted() +{ + PyFrameObject *current_frame = PyThreadState_Get()->frame; + return current_frame == NULL ? 0 : current_frame->f_restricted; +} + +int +Py_FlushLine() +{ + PyObject *f = PySys_GetObject("stdout"); + if (f == NULL) + return 0; + if (!PyFile_SoftSpace(f, 0)) + return 0; + return PyFile_WriteString("\n", f); +} + + +/* External interface to call any callable object. + The arg must be a tuple or NULL. */ + +#undef PyEval_CallObject +/* for backward compatibility: export this interface */ + +PyObject * +PyEval_CallObject(func, arg) + PyObject *func; + PyObject *arg; +{ + return PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL); +} +#define PyEval_CallObject(func,arg) \ + PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL) + +PyObject * +PyEval_CallObjectWithKeywords(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + ternaryfunc call; + PyObject *result; + + if (arg == NULL) + arg = PyTuple_New(0); + else if (!PyTuple_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "argument list must be a tuple"); + return NULL; + } + else + Py_INCREF(arg); + + if (kw != NULL && !PyDict_Check(kw)) { + PyErr_SetString(PyExc_TypeError, + "keyword list must be a dictionary"); + return NULL; + } + + if ((call = func->ob_type->tp_call) != NULL) + result = (*call)(func, arg, kw); + else if (PyMethod_Check(func) || PyFunction_Check(func)) + result = call_function(func, arg, kw); + else + result = call_builtin(func, arg, kw); + + Py_DECREF(arg); + + if (result == NULL && !PyErr_Occurred()) + PyErr_SetString(PyExc_SystemError, + "NULL result without error in call_object"); + + return result; +} + +static PyObject * +call_builtin(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + if (PyCFunction_Check(func)) { + PyCFunction meth = PyCFunction_GetFunction(func); + PyObject *self = PyCFunction_GetSelf(func); + int flags = PyCFunction_GetFlags(func); + if (!(flags & METH_VARARGS)) { + int size = PyTuple_Size(arg); + if (size == 1) + arg = PyTuple_GET_ITEM(arg, 0); + else if (size == 0) + arg = NULL; + } + if (flags & METH_KEYWORDS) + return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); + if (kw != NULL && PyDict_Size(kw) != 0) { + PyErr_SetString(PyExc_TypeError, + "this function takes no keyword arguments"); + return NULL; + } + return (*meth)(self, arg); + } + if (PyClass_Check(func)) { + return PyInstance_New(func, arg, kw); + } + if (PyInstance_Check(func)) { + PyObject *res, *call = PyObject_GetAttrString(func,"__call__"); + if (call == NULL) { + PyErr_Clear(); + PyErr_SetString(PyExc_AttributeError, + "no __call__ method defined"); + return NULL; + } + res = PyEval_CallObjectWithKeywords(call, arg, kw); + Py_DECREF(call); + return res; + } + PyErr_Format(PyExc_TypeError, "call of non-function (type %s)", + func->ob_type->tp_name); + return NULL; +} + +static PyObject * +call_function(func, arg, kw) + PyObject *func; + PyObject *arg; + PyObject *kw; +{ + PyObject *class = NULL; /* == owner */ + PyObject *argdefs; + PyObject **d, **k; + int nk, nd; + PyObject *result; + + if (kw != NULL && !PyDict_Check(kw)) { + PyErr_BadInternalCall(); + return NULL; + } + + if (PyMethod_Check(func)) { + PyObject *self = PyMethod_Self(func); + class = PyMethod_Class(func); + func = PyMethod_Function(func); + if (self == NULL) { + /* Unbound methods must be called with an instance of + the class (or a derived class) as first argument */ + if (PyTuple_Size(arg) >= 1) { + self = PyTuple_GET_ITEM(arg, 0); + if (self != NULL && + PyInstance_Check(self) && + PyClass_IsSubclass((PyObject *) + (((PyInstanceObject *)self)->in_class), + class)) + /* Handy-dandy */ ; + else + self = NULL; + } + if (self == NULL) { + PyErr_SetString(PyExc_TypeError, + "unbound method must be called with class instance 1st argument"); + return NULL; + } + Py_INCREF(arg); + } + else { + int argcount = PyTuple_Size(arg); + PyObject *newarg = PyTuple_New(argcount + 1); + int i; + if (newarg == NULL) + return NULL; + Py_INCREF(self); + PyTuple_SET_ITEM(newarg, 0, self); + for (i = 0; i < argcount; i++) { + PyObject *v = PyTuple_GET_ITEM(arg, i); + Py_XINCREF(v); + PyTuple_SET_ITEM(newarg, i+1, v); + } + arg = newarg; + } + if (!PyFunction_Check(func)) { + result = PyEval_CallObjectWithKeywords(func, arg, kw); + Py_DECREF(arg); + return result; + } + } + else { + if (!PyFunction_Check(func)) { + PyErr_Format(PyExc_TypeError, + "call of non-function (type %s)", + func->ob_type->tp_name); + return NULL; + } + Py_INCREF(arg); + } + + argdefs = PyFunction_GetDefaults(func); + if (argdefs != NULL && PyTuple_Check(argdefs)) { + d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0); + nd = PyTuple_Size(argdefs); + } + else { + d = NULL; + nd = 0; + } + + if (kw != NULL) { + int pos, i; + nk = PyDict_Size(kw); + k = PyMem_NEW(PyObject *, 2*nk); + if (k == NULL) { + PyErr_NoMemory(); + Py_DECREF(arg); + return NULL; + } + pos = i = 0; + while (PyDict_Next(kw, &pos, &k[i], &k[i+1])) + i += 2; + nk = i/2; + /* XXX This is broken if the caller deletes dict items! */ + } + else { + k = NULL; + nk = 0; + } + + result = eval_code2( + (PyCodeObject *)PyFunction_GetCode(func), + PyFunction_GetGlobals(func), (PyObject *)NULL, + &PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg), + k, nk, + d, nd, + class); + + Py_DECREF(arg); + PyMem_XDEL(k); + + return result; +} + +#define SLICE_ERROR_MSG \ + "standard sequence type does not support step size other than one" + +static PyObject * +loop_subscript(v, w) + PyObject *v, *w; +{ + PySequenceMethods *sq = v->ob_type->tp_as_sequence; + int i; + if (sq == NULL || sq->sq_item == NULL) { + PyErr_SetString(PyExc_TypeError, "loop over non-sequence"); + return NULL; + } + i = PyInt_AsLong(w); + v = (*sq->sq_item)(v, i); + if (v) + return v; + if (PyErr_ExceptionMatches(PyExc_IndexError)) + PyErr_Clear(); + return NULL; +} + +static int +slice_index(v, pi) + PyObject *v; + int *pi; +{ + if (v != NULL) { + long x; + if (!PyInt_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "slice index must be int"); + return -1; + } + x = PyInt_AsLong(v); + /* Truncate -- very long indices are truncated anyway */ + if (x > INT_MAX) + x = INT_MAX; + else if (x < -INT_MAX) + x = 0; + *pi = x; + } + return 0; +} + +static PyObject * +apply_slice(u, v, w) /* return u[v:w] */ + PyObject *u, *v, *w; +{ + int ilow = 0, ihigh = INT_MAX; + if (slice_index(v, &ilow) != 0) + return NULL; + if (slice_index(w, &ihigh) != 0) + return NULL; + return PySequence_GetSlice(u, ilow, ihigh); +} + +static int +assign_slice(u, v, w, x) /* u[v:w] = x */ + PyObject *u, *v, *w, *x; +{ + int ilow = 0, ihigh = INT_MAX; + if (slice_index(v, &ilow) != 0) + return -1; + if (slice_index(w, &ihigh) != 0) + return -1; + if (x == NULL) + return PySequence_DelSlice(u, ilow, ihigh); + else + return PySequence_SetSlice(u, ilow, ihigh, x); +} + +static PyObject * +cmp_outcome(op, v, w) + int op; + register PyObject *v; + register PyObject *w; +{ + register int cmp; + register int res = 0; + switch (op) { + case IS: + case IS_NOT: + res = (v == w); + if (op == (int) IS_NOT) + res = !res; + break; + case IN: + case NOT_IN: + res = PySequence_Contains(w, v); + if (res < 0) + return NULL; + if (op == (int) NOT_IN) + res = !res; + break; + case EXC_MATCH: + res = PyErr_GivenExceptionMatches(v, w); + break; + default: + cmp = PyObject_Compare(v, w); + if (cmp && PyErr_Occurred()) + return NULL; + switch (op) { + case LT: res = cmp < 0; break; + case LE: res = cmp <= 0; break; + case EQ: res = cmp == 0; break; + case NE: res = cmp != 0; break; + case GT: res = cmp > 0; break; + case GE: res = cmp >= 0; break; + /* XXX no default? (res is initialized to 0 though) */ + } + } + v = res ? Py_True : Py_False; + Py_INCREF(v); + return v; +} + +static int +import_from(locals, v, name) + PyObject *locals; + PyObject *v; + PyObject *name; +{ + PyObject *w, *x; + if (!PyModule_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "import-from requires module object"); + return -1; + } + w = PyModule_GetDict(v); + if (PyString_AsString(name)[0] == '*') { + int pos, err; + PyObject *name, *value; + pos = 0; + while (PyDict_Next(w, &pos, &name, &value)) { + if (!PyString_Check(name) || + PyString_AsString(name)[0] == '_') + continue; + Py_INCREF(value); + err = PyDict_SetItem(locals, name, value); + Py_DECREF(value); + if (err != 0) + return -1; + } + return 0; + } + else { + x = PyDict_GetItem(w, name); + if (x == NULL) { + char buf[250]; + sprintf(buf, "cannot import name %.230s", + PyString_AsString(name)); + PyErr_SetString(PyExc_ImportError, buf); + return -1; + } + else + return PyDict_SetItem(locals, name, x); + } +} + +static PyObject * +build_class(methods, bases, name) + PyObject *methods; /* dictionary */ + PyObject *bases; /* tuple containing classes */ + PyObject *name; /* string */ +{ + int i, n; + if (!PyTuple_Check(bases)) { + PyErr_SetString(PyExc_SystemError, + "build_class with non-tuple bases"); + return NULL; + } + if (!PyDict_Check(methods)) { + PyErr_SetString(PyExc_SystemError, + "build_class with non-dictionary"); + return NULL; + } + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_SystemError, + "build_class witn non-string name"); + return NULL; + } + n = PyTuple_Size(bases); + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + if (!PyClass_Check(base)) { + /* Call the base's *type*, if it is callable. + This code is a hook for Donald Beaudry's + and Jim Fulton's type extensions. In + unexended Python it will never be triggered + since its types are not callable. + Ditto: call the bases's *class*, if it has + one. This makes the same thing possible + without writing C code. A true meta-object + protocol! */ + PyObject *basetype = (PyObject *)base->ob_type; + PyObject *callable = NULL; + if (PyCallable_Check(basetype)) + callable = basetype; + else + callable = PyObject_GetAttrString( + base, "__class__"); + if (callable) { + PyObject *args; + PyObject *newclass = NULL; + args = Py_BuildValue( + "(OOO)", name, bases, methods); + if (args != NULL) { + newclass = PyEval_CallObject( + callable, args); + Py_DECREF(args); + } + if (callable != basetype) { + Py_DECREF(callable); + } + return newclass; + } + PyErr_SetString(PyExc_TypeError, + "base is not a class object"); + return NULL; + } + } + return PyClass_New(bases, methods, name); +} + +static int +exec_statement(f, prog, globals, locals) + PyFrameObject *f; + PyObject *prog; + PyObject *globals; + PyObject *locals; +{ + char *s; + int n; + PyObject *v; + int plain = 0; + + if (PyTuple_Check(prog) && globals == Py_None && locals == Py_None && + ((n = PyTuple_Size(prog)) == 2 || n == 3)) { + /* Backward compatibility hack */ + globals = PyTuple_GetItem(prog, 1); + if (n == 3) + locals = PyTuple_GetItem(prog, 2); + prog = PyTuple_GetItem(prog, 0); + } + if (globals == Py_None) { + globals = PyEval_GetGlobals(); + if (locals == Py_None) { + locals = PyEval_GetLocals(); + plain = 1; + } + } + else if (locals == Py_None) + locals = globals; + if (!PyString_Check(prog) && + !PyCode_Check(prog) && + !PyFile_Check(prog)) { + PyErr_SetString(PyExc_TypeError, + "exec 1st arg must be string, code or file object"); + return -1; + } + if (!PyDict_Check(globals) || !PyDict_Check(locals)) { + PyErr_SetString(PyExc_TypeError, + "exec 2nd/3rd args must be dict or None"); + return -1; + } + if (PyDict_GetItemString(globals, "__builtins__") == NULL) + PyDict_SetItemString(globals, "__builtins__", f->f_builtins); + if (PyCode_Check(prog)) { + v = PyEval_EvalCode((PyCodeObject *) prog, + globals, locals); + if (v == NULL) + return -1; + Py_DECREF(v); + return 0; + } + if (PyFile_Check(prog)) { + FILE *fp = PyFile_AsFile(prog); + char *name = PyString_AsString(PyFile_Name(prog)); + if (PyRun_File(fp, name, Py_file_input, + globals, locals) == NULL) + return -1; + return 0; + } + s = PyString_AsString(prog); + if ((int)strlen(s) != PyString_Size(prog)) { + PyErr_SetString(PyExc_ValueError, + "embedded '\\0' in exec string"); + return -1; + } + v = PyRun_String(s, Py_file_input, globals, locals); + if (v == NULL) + return -1; + Py_DECREF(v); + if (plain) + PyFrame_LocalsToFast(f, 0); + return 0; +} + +/* Hack for ni.py */ +static PyObject * +find_from_args(f, nexti) + PyFrameObject *f; + int nexti; +{ + int opcode; + int oparg; + PyObject *list, *name; + unsigned char *next_instr; + + _PyCode_GETCODEPTR(f->f_code, &next_instr); + next_instr += nexti; + + opcode = (*next_instr++); + if (opcode != IMPORT_FROM) { + Py_INCREF(Py_None); + return Py_None; + } + + list = PyList_New(0); + if (list == NULL) + return NULL; + + do { + oparg = (next_instr[1]<<8) + next_instr[0]; + next_instr += 2; + name = Getnamev(f, oparg); + if (PyList_Append(list, name) < 0) { + Py_DECREF(list); + break; + } + opcode = (*next_instr++); + } while (opcode == IMPORT_FROM); + + return list; +} + + +#ifdef DYNAMIC_EXECUTION_PROFILE + +PyObject * +getarray(a) + long a[256]; +{ + int i; + PyObject *l = PyList_New(256); + if (l == NULL) return NULL; + for (i = 0; i < 256; i++) { + PyObject *x = PyInt_FromLong(a[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + for (i = 0; i < 256; i++) + a[i] = 0; + return l; +} + +PyObject * +_Py_GetDXProfile(self, args) + PyObject *self, *args; +{ +#ifndef DXPAIRS + return getarray(dxp); +#else + int i; + PyObject *l = PyList_New(257); + if (l == NULL) return NULL; + for (i = 0; i < 257; i++) { + PyObject *x = getarray(dxpairs[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + return l; +#endif +} + +#endif diff --git a/src/main/resource/testFiles/gzip/prevFiles/prev_051ed8_8b83dc_gzip.c b/src/main/resource/testFiles/gzip/prevFiles/prev_051ed8_8b83dc_gzip.c new file mode 100644 index 0000000..5b4474a --- /dev/null +++ b/src/main/resource/testFiles/gzip/prevFiles/prev_051ed8_8b83dc_gzip.c @@ -0,0 +1,2165 @@ +/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + + Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2018 Free Software + Foundation, Inc. + Copyright (C) 1992-1993 Jean-loup Gailly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* + * The unzip code was written and put in the public domain by Mark Adler. + * Portions of the lzw code are derived from the public domain 'compress' + * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, + * Ken Turkowski, Dave Mack and Peter Jannesen. + * + * See the license_msg below and the file COPYING for the software license. + * See the file algorithm.doc for the compression algorithms and file formats. + */ + +static char const *const license_msg[] = { +"Copyright (C) 2018 Free Software Foundation, Inc.", +"Copyright (C) 1993 Jean-loup Gailly.", +"This is free software. You may redistribute copies of it under the terms of", +"the GNU General Public License .", +"There is NO WARRANTY, to the extent permitted by law.", +0}; + +/* Compress files with zip algorithm and 'compress' interface. + * See help() function below for all options. + * Outputs: + * file.gz: compressed file with same mode, owner, and utimes + * or stdout with -c option or if stdin used as input. + * If the output file name had to be truncated, the original name is kept + * in the compressed file. + * On MSDOS, file.tmp -> file.tmz. + * + * Using gz on MSDOS would create too many file name conflicts. For + * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for + * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz. + * I also considered 12345678.txt -> 12345txt.gz but this truncates the name + * too heavily. There is no ideal solution given the MSDOS 8+3 limitation. + * + * For the meaning of all compilation flags, see comments in Makefile.in. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tailor.h" +#include "gzip.h" +#include "intprops.h" +#include "lzw.h" +#include "revision.h" +#include "timespec.h" + +#include "dirname.h" +#include "dosname.h" +#include "fcntl--.h" +#include "getopt.h" +#include "ignore-value.h" +#include "stat-time.h" +#include "version.h" +#include "xalloc.h" +#include "yesno.h" + + /* configuration */ + +#include +#include +#include +#include + +#ifndef NO_DIR +# define NO_DIR 0 +#endif +#if !NO_DIR +# include +# include +#endif + +#ifndef NO_UTIME +# include +#endif + +#ifndef MAX_PATH_LEN +# define MAX_PATH_LEN 1024 /* max pathname length */ +#endif + +#ifndef SEEK_END +# define SEEK_END 2 +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +#ifdef off_t + off_t lseek (int fd, off_t offset, int whence); +#endif + +#ifndef OFF_T_MAX +# define OFF_T_MAX TYPE_MAXIMUM (off_t) +#endif + +#ifndef HAVE_WORKING_O_NOFOLLOW +# define HAVE_WORKING_O_NOFOLLOW 0 +#endif + +/* Separator for file name parts (see shorten_name()) */ +#ifdef NO_MULTIPLE_DOTS +# define PART_SEP "-" +#else +# define PART_SEP "." +#endif + + /* global buffers */ + +DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA); +DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); +DECLARE(ush, d_buf, DIST_BUFSIZE); +DECLARE(uch, window, 2L*WSIZE); +#ifndef MAXSEG_64K + DECLARE(ush, tab_prefix, 1L<.", + 0}; + char const *const *p = help_msg; + + printf ("Usage: %s [OPTION]... [FILE]...\n", program_name); + while (*p) printf ("%s\n", *p++); +} + +/* ======================================================================== */ +local void license() +{ + char const *const *p = license_msg; + + printf ("%s %s\n", program_name, Version); + while (*p) printf ("%s\n", *p++); +} + +/* ======================================================================== */ +local void version() +{ + license (); + printf ("\n"); + printf ("Written by Jean-loup Gailly.\n"); +} + +local void progerror (char const *string) +{ + int e = errno; + fprintf (stderr, "%s: ", program_name); + errno = e; + perror(string); + exit_code = ERROR; +} + +/* ======================================================================== */ +int main (int argc, char **argv) +{ + int file_count; /* number of files to process */ + size_t proglen; /* length of program_name */ + char **argv_copy; + int env_argc; + char **env_argv; + + EXPAND(argc, argv); /* wild card expansion if necessary */ + + program_name = gzip_base_name (argv[0]); + proglen = strlen (program_name); + + /* Suppress .exe for MSDOS and OS/2: */ + if (4 < proglen && strequ (program_name + proglen - 4, ".exe")) + program_name[proglen - 4] = '\0'; + + /* Add options in GZIP environment variable if there is one */ + argv_copy = argv; + env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR); + env_argv = env ? argv_copy : NULL; + +#ifndef GNU_STANDARD +# define GNU_STANDARD 1 +#endif +#if !GNU_STANDARD + /* For compatibility with old compress, use program name as an option. + * Unless you compile with -DGNU_STANDARD=0, this program will behave as + * gzip even if it is invoked under the name gunzip or zcat. + * + * Systems which do not support links can still use -d or -dc. + * Ignore an .exe extension for MSDOS and OS/2. + */ + if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */ + || strncmp (program_name, "gun", 3) == 0) /* gunzip */ + decompress = 1; + else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */ + || strequ (program_name, "gzcat")) /* gzcat */ + decompress = to_stdout = 1; +#endif + + z_suffix = Z_SUFFIX; + z_len = strlen(z_suffix); + + while (true) { + int optc; + int longind = -1; + + if (env_argv) + { + if (env_argv[optind] && strequ (env_argv[optind], "--")) + optc = ENV_OPTION + '-'; + else + { + optc = getopt_long (env_argc, env_argv, shortopts, longopts, + &longind); + if (0 <= optc) + optc += ENV_OPTION; + else + { + if (optind != env_argc) + { + fprintf (stderr, + ("%s: %s: non-option in "OPTIONS_VAR + " environment variable\n"), + program_name, env_argv[optind]); + try_help (); + } + + /* Wait until here before warning, so that GZIP='-q' + doesn't warn. */ + if (env_argc != 1 && !quiet) + fprintf (stderr, + ("%s: warning: "OPTIONS_VAR" environment variable" + " is deprecated; use an alias or script\n"), + program_name); + + /* Start processing ARGC and ARGV instead. */ + free (env_argv); + env_argv = NULL; + optind = 1; + longind = -1; + } + } + } + + if (!env_argv) + optc = getopt_long (argc, argv, shortopts, longopts, &longind); + if (optc < 0) + break; + + switch (optc) { + case 'a': + ascii = 1; break; + case 'b': + maxbits = atoi(optarg); + for (; *optarg; optarg++) + if (! ('0' <= *optarg && *optarg <= '9')) + { + fprintf (stderr, "%s: -b operand is not an integer\n", + program_name); + try_help (); + } + break; + case 'c': + to_stdout = 1; break; + case 'd': + decompress = 1; break; + case 'f': + force++; break; + case 'h': case 'H': + help (); finish_out (); break; + case 'k': + keep = 1; break; + case 'l': + list = decompress = to_stdout = 1; break; + case 'L': + license (); finish_out (); break; + case 'm': /* undocumented, may change later */ + no_time = 1; break; + case 'M': /* undocumented, may change later */ + no_time = 0; break; + case 'n': + case 'n' + ENV_OPTION: + no_name = no_time = 1; break; + case 'N': + case 'N' + ENV_OPTION: + no_name = no_time = 0; break; + case PRESUME_INPUT_TTY_OPTION: + presume_input_tty = true; break; + case 'q': + case 'q' + ENV_OPTION: + quiet = 1; verbose = 0; break; + case 'r': +#if NO_DIR + fprintf (stderr, "%s: -r not supported on this system\n", + program_name); + try_help (); +#else + recursive = 1; +#endif + break; + + case RSYNCABLE_OPTION: + case RSYNCABLE_OPTION + ENV_OPTION: + rsync = 1; + break; + case 'S': +#ifdef NO_MULTIPLE_DOTS + if (*optarg == '.') optarg++; +#endif + z_len = strlen(optarg); + z_suffix = optarg; + break; + case SYNCHRONOUS_OPTION: + synchronous = true; + break; + case 't': + test = decompress = to_stdout = 1; + break; + case 'v': + case 'v' + ENV_OPTION: + verbose++; quiet = 0; break; + case 'V': + version (); finish_out (); break; + case 'Z': +#ifdef LZW + do_lzw = 1; break; +#else + fprintf(stderr, "%s: -Z not supported in this version\n", + program_name); + try_help (); + break; +#endif + case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION: + case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION: + case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION: + optc -= ENV_OPTION; + FALLTHROUGH; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + level = optc - '0'; + break; + + default: + if (ENV_OPTION <= optc && optc != ENV_OPTION + '?') + { + /* Output a diagnostic, since getopt_long didn't. */ + fprintf (stderr, "%s: ", program_name); + if (longind < 0) + fprintf (stderr, "-%c: ", optc - ENV_OPTION); + else + fprintf (stderr, "--%s: ", longopts[longind].name); + fprintf (stderr, ("option not valid in "OPTIONS_VAR + " environment variable\n")); + } + try_help (); + } + } /* loop on all arguments */ + + /* By default, save name and timestamp on compression but do not + * restore them on decompression. + */ + if (no_time < 0) no_time = decompress; + if (no_name < 0) no_name = decompress; + + file_count = argc - optind; + +#if O_BINARY +#else + if (ascii && !quiet) { + fprintf(stderr, "%s: option --ascii ignored on this system\n", + program_name); + } +#endif + if (z_len == 0 || z_len > MAX_SUFFIX) { + fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix); + do_exit(ERROR); + } + + if (do_lzw && !decompress) work = lzw; + + /* Allocate all global buffers (for DYN_ALLOC option) */ + ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA); + ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); + ALLOC(ush, d_buf, DIST_BUFSIZE); + ALLOC(uch, window, 2L*WSIZE); +#ifndef MAXSEG_64K + ALLOC(ush, tab_prefix, 1L< s && ! ISSLASH (suffix[slen - s - 1]) + && strequ(suffix + slen - s, *suf)) { + match = name+nlen-s; + break; + } + } while (*++suf != NULL); + free(z_lower); + + return match; +} + + +/* Open file NAME with the given flags and store its status + into *ST. Return a file descriptor to the newly opened file, or -1 + (setting errno) on failure. */ +static int +open_and_stat (char *name, int flags, struct stat *st) +{ + int fd; + int atfd = AT_FDCWD; + char const *base = name; + + /* Refuse to follow symbolic links unless -c or -f. */ + if (!to_stdout && !force) + { + if (HAVE_WORKING_O_NOFOLLOW) + flags |= O_NOFOLLOW; + else + { +#ifdef S_ISLNK + if (lstat (name, st) != 0) + return -1; + else if (S_ISLNK (st->st_mode)) + { + errno = ELOOP; + return -1; + } +#endif + } + } + + if (!keep) + { + char const *b = last_component (name); + int f = atdir_set (name, b - name); + if (0 <= f) + { + base = b; + atfd = f; + } + } + + fd = openat (atfd, base, flags); + if (0 <= fd && fstat (fd, st) != 0) + { + int e = errno; + close (fd); + errno = e; + return -1; + } + return fd; +} + + +/* ======================================================================== + * Set ifname to the input file name (with a suffix appended if necessary) + * and istat to its stats. For decompression, if no file exists with the + * original name, try adding successively z_suffix, .gz, .z, -z and .Z. + * For MSDOS, we try only z_suffix and z. + * Return an open file descriptor or -1. + */ +static int +open_input_file (iname, sbuf) + char *iname; + struct stat *sbuf; +{ + int ilen; /* strlen(ifname) */ + int z_suffix_errno = 0; + static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL}; + char const **suf = suffixes; + char const *s; +#ifdef NO_MULTIPLE_DOTS + char *dot; /* pointer to ifname extension, or NULL */ +#endif + int fd; + int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY + | (ascii && !decompress ? 0 : O_BINARY)); + + *suf = z_suffix; + + if (sizeof ifname - 1 <= strlen (iname)) + goto name_too_long; + + strcpy(ifname, iname); + + /* If input file exists, return OK. */ + fd = open_and_stat (ifname, open_flags, sbuf); + if (0 <= fd) + return fd; + + if (!decompress || errno != ENOENT) { + progerror(ifname); + return -1; + } + /* File.ext doesn't exist. Try adding a suffix. */ + s = get_suffix(ifname); + if (s != NULL) { + progerror(ifname); /* ifname already has z suffix and does not exist */ + return -1; + } +#ifdef NO_MULTIPLE_DOTS + dot = strrchr(ifname, '.'); + if (dot == NULL) { + strcat(ifname, "."); + dot = strrchr(ifname, '.'); + } +#endif + ilen = strlen(ifname); + if (strequ(z_suffix, ".gz")) suf++; + + /* Search for all suffixes */ + do { + char const *s0 = s = *suf; + strcpy (ifname, iname); +#ifdef NO_MULTIPLE_DOTS + if (*s == '.') s++; + if (*dot == '\0') strcpy (dot, "."); +#endif +#ifdef MAX_EXT_CHARS + if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1)) + dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0'; +#endif + if (sizeof ifname <= ilen + strlen (s)) + goto name_too_long; + strcat(ifname, s); + fd = open_and_stat (ifname, open_flags, sbuf); + if (0 <= fd) + return fd; + if (errno != ENOENT) + { + progerror (ifname); + return -1; + } + if (strequ (s0, z_suffix)) + z_suffix_errno = errno; + } while (*++suf != NULL); + + /* No suffix found, complain using z_suffix: */ + strcpy(ifname, iname); +#ifdef NO_MULTIPLE_DOTS + if (*dot == '\0') strcpy(dot, "."); +#endif +#ifdef MAX_EXT_CHARS + if (MAX_EXT_CHARS < z_len + strlen (dot + 1)) + dot[MAX_EXT_CHARS + 1 - z_len] = '\0'; +#endif + strcat(ifname, z_suffix); + errno = z_suffix_errno; + progerror(ifname); + return -1; + + name_too_long: + fprintf (stderr, "%s: %s: file name too long\n", program_name, iname); + exit_code = ERROR; + return -1; +} + +/* ======================================================================== + * Generate ofname given ifname. Return OK, or WARNING if file must be skipped. + * Sets save_orig_name to true if the file name has been truncated. + */ +local int make_ofname() +{ + char *suff; /* ofname z suffix */ + + strcpy(ofname, ifname); + /* strip a version number if any and get the gzip suffix if present: */ + suff = get_suffix(ofname); + + if (decompress) { + if (suff == NULL) { + /* With -t or -l, try all files (even without .gz suffix) + * except with -r (behave as with just -dr). + */ + if (!recursive && (list || test)) return OK; + + /* Avoid annoying messages with -r */ + if (verbose || (!recursive && !quiet)) { + WARN((stderr,"%s: %s: unknown suffix -- ignored\n", + program_name, ifname)); + } + return WARNING; + } + /* Make a special case for .tgz and .taz: */ + strlwr(suff); + if (strequ(suff, ".tgz") || strequ(suff, ".taz")) { + strcpy(suff, ".tar"); + } else { + *suff = '\0'; /* strip the z suffix */ + } + /* ofname might be changed later if infile contains an original name */ + + } else if (suff && ! force) { + /* Avoid annoying messages with -r (see treat_dir()) */ + if (verbose || (!recursive && !quiet)) { + /* Don't use WARN, as it affects exit status. */ + fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n", + program_name, ifname, suff); + } + return WARNING; + } else { + save_orig_name = 0; + +#ifdef NO_MULTIPLE_DOTS + suff = strrchr(ofname, '.'); + if (suff == NULL) { + if (sizeof ofname <= strlen (ofname) + 1) + goto name_too_long; + strcat(ofname, "."); +# ifdef MAX_EXT_CHARS + if (strequ(z_suffix, "z")) { + if (sizeof ofname <= strlen (ofname) + 2) + goto name_too_long; + strcat(ofname, "gz"); /* enough room */ + return OK; + } + /* On the Atari and some versions of MSDOS, + * ENAMETOOLONG does not work correctly. So we + * must truncate here. + */ + } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) { + suff[MAX_SUFFIX+1-z_len] = '\0'; + save_orig_name = 1; +# endif + } +#endif /* NO_MULTIPLE_DOTS */ + if (sizeof ofname <= strlen (ofname) + z_len) + goto name_too_long; + strcat(ofname, z_suffix); + + } /* decompress ? */ + return OK; + + name_too_long: + WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname)); + return WARNING; +} + +/* Discard NBYTES input bytes from the input, or up through the next + zero byte if NBYTES == (size_t) -1. If FLAGS say that the header + CRC should be computed, update the CRC accordingly. */ +static void +discard_input_bytes (nbytes, flags) + size_t nbytes; + unsigned int flags; +{ + while (nbytes != 0) + { + uch c = get_byte (); + if (flags & HEADER_CRC) + updcrc (&c, 1); + if (nbytes != (size_t) -1) + nbytes--; + else if (! c) + break; + } +} + +/* ======================================================================== + * Check the magic number of the input file and update ofname if an + * original name was given and to_stdout is not set. + * Return the compression method, -1 for error, -2 for warning. + * Set inptr to the offset of the next byte to be processed. + * Updates time_stamp if there is one and neither -m nor -n is used. + * This function may be called repeatedly for an input file consisting + * of several contiguous gzip'ed members. + * IN assertions: there is at least one remaining compressed member. + * If the member is a zip file, it must be the only one. + */ +local int get_method(in) + int in; /* input file descriptor */ +{ + uch flags; /* compression flags */ + uch magic[10]; /* magic header */ + int imagic0; /* first magic byte or EOF */ + int imagic1; /* like magic[1], but can represent EOF */ + ulg stamp; /* timestamp */ + + /* If --force and --stdout, zcat == cat, so do not complain about + * premature end of file: use try_byte instead of get_byte. + */ + if (force && to_stdout) { + imagic0 = try_byte(); + magic[0] = imagic0; + imagic1 = try_byte (); + magic[1] = imagic1; + /* If try_byte returned EOF, magic[1] == (char) EOF. */ + } else { + magic[0] = get_byte (); + imagic0 = 0; + if (magic[0]) { + magic[1] = get_byte (); + imagic1 = 0; /* avoid lint warning */ + } else { + imagic1 = try_byte (); + magic[1] = imagic1; + } + } + method = -1; /* unknown yet */ + part_nb++; /* number of parts in gzip file */ + header_bytes = 0; + last_member = 0; + /* assume multiple members in gzip file except for record oriented I/O */ + + if (memcmp(magic, GZIP_MAGIC, 2) == 0 + || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) { + + method = (int)get_byte(); + if (method != DEFLATED) { + fprintf(stderr, + "%s: %s: unknown method %d -- not supported\n", + program_name, ifname, method); + exit_code = ERROR; + return -1; + } + work = unzip; + flags = (uch)get_byte(); + + if ((flags & ENCRYPTED) != 0) { + fprintf(stderr, + "%s: %s is encrypted -- not supported\n", + program_name, ifname); + exit_code = ERROR; + return -1; + } + if ((flags & RESERVED) != 0) { + fprintf(stderr, + "%s: %s has flags 0x%x -- not supported\n", + program_name, ifname, flags); + exit_code = ERROR; + if (force <= 1) return -1; + } + stamp = (ulg)get_byte(); + stamp |= ((ulg)get_byte()) << 8; + stamp |= ((ulg)get_byte()) << 16; + stamp |= ((ulg)get_byte()) << 24; + if (stamp != 0 && !no_time) + { + if (stamp <= TYPE_MAXIMUM (time_t)) + { + time_stamp.tv_sec = stamp; + time_stamp.tv_nsec = 0; + } + else + { + WARN ((stderr, + "%s: %s: MTIME %lu out of range for this platform\n", + program_name, ifname, stamp)); + time_stamp.tv_sec = TYPE_MAXIMUM (time_t); + time_stamp.tv_nsec = TIMESPEC_RESOLUTION - 1; + } + } + + magic[8] = get_byte (); /* Ignore extra flags. */ + magic[9] = get_byte (); /* Ignore OS type. */ + + if (flags & HEADER_CRC) + { + magic[2] = DEFLATED; + magic[3] = flags; + magic[4] = stamp & 0xff; + magic[5] = (stamp >> 8) & 0xff; + magic[6] = (stamp >> 16) & 0xff; + magic[7] = stamp >> 24; + updcrc (NULL, 0); + updcrc (magic, 10); + } + + if ((flags & EXTRA_FIELD) != 0) { + uch lenbuf[2]; + unsigned int len = lenbuf[0] = get_byte (); + len |= (lenbuf[1] = get_byte ()) << 8; + if (verbose) { + fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n", + program_name, ifname, len); + } + if (flags & HEADER_CRC) + updcrc (lenbuf, 2); + discard_input_bytes (len, flags); + } + + /* Get original file name if it was truncated */ + if ((flags & ORIG_NAME) != 0) { + if (no_name || (to_stdout && !list) || part_nb > 1) { + /* Discard the old name */ + discard_input_bytes (-1, flags); + } else { + /* Copy the base name. Keep a directory prefix intact. */ + char *p = gzip_base_name (ofname); + char *base = p; + for (;;) { + *p = (char) get_byte (); + if (*p++ == '\0') break; + if (p >= ofname+sizeof(ofname)) { + gzip_error ("corrupted input -- file name too large"); + } + } + if (flags & HEADER_CRC) + updcrc ((uch *) base, p - base); + p = gzip_base_name (base); + memmove (base, p, strlen (p) + 1); + /* If necessary, adapt the name to local OS conventions: */ + if (!list) { + MAKE_LEGAL_NAME(base); + if (base) list=0; /* avoid warning about unused variable */ + } + } /* no_name || to_stdout */ + } /* ORIG_NAME */ + + /* Discard file comment if any */ + if ((flags & COMMENT) != 0) { + discard_input_bytes (-1, flags); + } + + if (flags & HEADER_CRC) + { + unsigned int crc16 = updcrc (magic, 0) & 0xffff; + unsigned int header16 = get_byte (); + header16 |= ((unsigned int) get_byte ()) << 8; + if (header16 != crc16) + { + fprintf (stderr, + "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n", + program_name, ifname, header16, crc16); + exit_code = ERROR; + if (force <= 1) + return -1; + } + } + + if (part_nb == 1) { + header_bytes = inptr + 2*4; /* include crc and size */ + } + + } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2 + && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) { + /* To simplify the code, we support a zip file when alone only. + * We are thus guaranteed that the entire local header fits in inbuf. + */ + inptr = 0; + work = unzip; + if (check_zipfile(in) != OK) return -1; + /* check_zipfile may get ofname from the local header */ + last_member = 1; + + } else if (memcmp(magic, PACK_MAGIC, 2) == 0) { + work = unpack; + method = PACKED; + + } else if (memcmp(magic, LZW_MAGIC, 2) == 0) { + work = unlzw; + method = COMPRESSED; + last_member = 1; + + } else if (memcmp(magic, LZH_MAGIC, 2) == 0) { + work = unlzh; + method = LZHED; + last_member = 1; + + } else if (force && to_stdout && !list) { /* pass input unchanged */ + method = STORED; + work = copy; + if (imagic1 != EOF) + inptr--; + last_member = 1; + if (imagic0 != EOF) { + write_buf (STDOUT_FILENO, magic, 1); + bytes_out++; + } + } + if (method >= 0) return method; + + if (part_nb == 1) { + fprintf (stderr, "\n%s: %s: not in gzip format\n", + program_name, ifname); + exit_code = ERROR; + return -1; + } else { + if (magic[0] == 0) + { + int inbyte; + for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ()) + continue; + if (inbyte == EOF) + { + if (verbose) + WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n", + program_name, ifname)); + return -3; + } + } + + WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n", + program_name, ifname)); + return -2; + } +} + +/* ======================================================================== + * Display the characteristics of the compressed file. + * If the given method is < 0, display the accumulated totals. + * IN assertions: time_stamp, header_bytes and ifile_size are initialized. + */ +local void do_list(ifd, method) + int ifd; /* input file descriptor */ + int method; /* compression method */ +{ + ulg crc; /* original crc */ + static int first_time = 1; + static char const *const methods[MAX_METHODS] = { + "store", /* 0 */ + "compr", /* 1 */ + "pack ", /* 2 */ + "lzh ", /* 3 */ + "", "", "", "", /* 4 to 7 reserved */ + "defla"}; /* 8 */ + int positive_off_t_width = 1; + off_t o; + + for (o = OFF_T_MAX; 9 < o; o /= 10) { + positive_off_t_width++; + } + + if (first_time && method >= 0) { + first_time = 0; + if (verbose) { + printf("method crc date time "); + } + if (!quiet) { + printf("%*.*s %*.*s ratio uncompressed_name\n", + positive_off_t_width, positive_off_t_width, "compressed", + positive_off_t_width, positive_off_t_width, "uncompressed"); + } + } else if (method < 0) { + if (total_in <= 0 || total_out <= 0) return; + if (verbose) { + printf(" "); + } + if (verbose || !quiet) { + fprint_off(stdout, total_in, positive_off_t_width); + printf(" "); + fprint_off(stdout, total_out, positive_off_t_width); + printf(" "); + } + display_ratio(total_out-(total_in-header_bytes), total_out, stdout); + /* header_bytes is not meaningful but used to ensure the same + * ratio if there is a single file. + */ + printf(" (totals)\n"); + return; + } + crc = (ulg)~0; /* unknown */ + bytes_out = -1L; + bytes_in = ifile_size; + + if (method == DEFLATED && !last_member) { + /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files. + * If the lseek fails, we could use read() to get to the end, but + * --list is used to get quick results. + * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if + * you are not concerned about speed. + */ + bytes_in = lseek(ifd, (off_t)(-8), SEEK_END); + if (bytes_in != -1L) { + uch buf[8]; + bytes_in += 8L; + if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) { + read_error(); + } + crc = LG(buf); + bytes_out = LG(buf+4); + } + } + + if (verbose) + { + static char const month_abbr[][4] + = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + struct tm *tm = localtime (&time_stamp.tv_sec); + printf ("%5s %08lx ", methods[method], crc); + if (tm) + printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon], + tm->tm_mday, tm->tm_hour, tm->tm_min); + else + printf ("??? ?? ??:?? "); + } + fprint_off(stdout, bytes_in, positive_off_t_width); + printf(" "); + fprint_off(stdout, bytes_out, positive_off_t_width); + printf(" "); + if (bytes_in == -1L) { + total_in = -1L; + bytes_in = bytes_out = header_bytes = 0; + } else if (total_in >= 0) { + total_in += bytes_in; + } + if (bytes_out == -1L) { + total_out = -1L; + bytes_in = bytes_out = header_bytes = 0; + } else if (total_out >= 0) { + total_out += bytes_out; + } + display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout); + printf(" %s\n", ofname); +} + +/* ======================================================================== + * Shorten the given name by one character, or replace a .tar extension + * with .tgz. Truncate the last part of the name which is longer than + * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name + * has only parts shorter than MIN_PART truncate the longest part. + * For decompression, just remove the last character of the name. + * + * IN assertion: for compression, the suffix of the given name is z_suffix. + */ +local void shorten_name(name) + char *name; +{ + int len; /* length of name without z_suffix */ + char *trunc = NULL; /* character to be truncated */ + int plen; /* current part length */ + int min_part = MIN_PART; /* current minimum part length */ + char *p; + + len = strlen(name); + if (decompress) { + if (len <= 1) + gzip_error ("name too short"); + name[len-1] = '\0'; + return; + } + p = get_suffix(name); + if (! p) + gzip_error ("can't recover suffix\n"); + *p = '\0'; + save_orig_name = 1; + + /* compress 1234567890.tar to 1234567890.tgz */ + if (len > 4 && strequ(p-4, ".tar")) { + strcpy(p-4, ".tgz"); + return; + } + /* Try keeping short extensions intact: + * 1234.678.012.gz -> 123.678.012.gz + */ + do { + p = last_component (name); + while (*p) { + plen = strcspn(p, PART_SEP); + p += plen; + if (plen > min_part) trunc = p-1; + if (*p) p++; + } + } while (trunc == NULL && --min_part != 0); + + if (trunc != NULL) { + do { + trunc[0] = trunc[1]; + } while (*trunc++); + trunc--; + } else { + trunc = strrchr(name, PART_SEP[0]); + if (!trunc) + gzip_error ("internal error in shorten_name"); + if (trunc[1] == '\0') trunc--; /* force truncation */ + } + strcpy(trunc, z_suffix); +} + +/* ======================================================================== + * The compressed file already exists, so ask for confirmation. + * Return ERROR if the file must be skipped. + */ +local int check_ofname() +{ + /* Ask permission to overwrite the existing file */ + if (!force) { + int ok = 0; + fprintf (stderr, "%s: %s already exists;", program_name, ofname); + if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) { + fprintf(stderr, " do you wish to overwrite (y or n)? "); + fflush(stderr); + ok = yesno(); + } + if (!ok) { + fprintf(stderr, "\tnot overwritten\n"); + if (exit_code == OK) exit_code = WARNING; + return ERROR; + } + } + if (xunlink (ofname)) { + progerror(ofname); + return ERROR; + } + return OK; +} + +/* Change the owner and group of a file. FD is a file descriptor for + the file and NAME its name. Change it to user UID and to group GID. + If UID or GID is -1, though, do not change the corresponding user + or group. */ +#if ! (HAVE_FCHOWN || HAVE_CHOWN) +/* The types uid_t and gid_t do not exist on mingw, so don't assume them. */ +# define do_chown(fd, name, uid, gid) ((void) 0) +#else +static void +do_chown (int fd, char const *name, uid_t uid, gid_t gid) +{ +# if HAVE_FCHOWN + ignore_value (fchown (fd, uid, gid)); +# else + ignore_value (chown (name, uid, gid)); +# endif +} +#endif + +/* ======================================================================== + * Copy modes, times, ownership from input file to output file. + * IN assertion: to_stdout is false. + */ +local void copy_stat(ifstat) + struct stat *ifstat; +{ + mode_t mode = ifstat->st_mode & S_IRWXUGO; + int r; + +#ifndef NO_UTIME + bool restoring; + struct timespec timespec[2]; + timespec[0] = get_stat_atime (ifstat); + timespec[1] = get_stat_mtime (ifstat); + restoring = (decompress && 0 <= time_stamp.tv_nsec + && ! (timespec[1].tv_sec == time_stamp.tv_sec + && timespec[1].tv_nsec == time_stamp.tv_nsec)); + if (restoring) + timespec[1] = time_stamp; + + if (fdutimens (ofd, ofname, timespec) == 0) + { + if (restoring && 1 < verbose) { + fprintf(stderr, "%s: timestamp restored\n", ofname); + } + } + else + { + int e = errno; + WARN ((stderr, "%s: ", program_name)); + if (!quiet) + { + errno = e; + perror (ofname); + } + } +#endif + + /* Change the group first, then the permissions, then the owner. + That way, the permissions will be correct on systems that allow + users to give away files, without introducing a security hole. + Security depends on permissions not containing the setuid or + setgid bits. */ + + do_chown (ofd, ofname, -1, ifstat->st_gid); + +#if HAVE_FCHMOD + r = fchmod (ofd, mode); +#else + r = chmod (ofname, mode); +#endif + if (r != 0) { + int e = errno; + WARN ((stderr, "%s: ", program_name)); + if (!quiet) { + errno = e; + perror(ofname); + } + } + + do_chown (ofd, ofname, ifstat->st_uid, -1); +} + +#if ! NO_DIR + +/* ======================================================================== + * Recurse through the given directory. + */ +local void treat_dir (fd, dir) + int fd; + char *dir; +{ + DIR *dirp; + char nbuf[MAX_PATH_LEN]; + char *entries; + char const *entry; + size_t entrylen; + + dirp = fdopendir (fd); + + if (dirp == NULL) { + progerror(dir); + close (fd); + return ; + } + + entries = streamsavedir (dirp, SAVEDIR_SORT_NONE); + if (! entries) + progerror (dir); + if (closedir (dirp) != 0) + progerror (dir); + if (! entries) + return; + + for (entry = entries; *entry; entry += entrylen + 1) { + size_t len = strlen (dir); + entrylen = strlen (entry); + if (strequ (entry, ".") || strequ (entry, "..")) + continue; + if (len + entrylen < MAX_PATH_LEN - 2) { + strcpy(nbuf,dir); + if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1])) + nbuf[len++] = '/'; + strcpy (nbuf + len, entry); + treat_file(nbuf); + } else { + fprintf(stderr,"%s: %s/%s: pathname too long\n", + program_name, dir, entry); + exit_code = ERROR; + } + } + free (entries); +} +#endif /* ! NO_DIR */ + +/* Make sure signals get handled properly. */ + +static void +install_signal_handlers () +{ + int nsigs = sizeof handled_sig / sizeof handled_sig[0]; + int i; + struct sigaction act; + + sigemptyset (&caught_signals); + for (i = 0; i < nsigs; i++) + { + sigaction (handled_sig[i], NULL, &act); + if (act.sa_handler != SIG_IGN) + sigaddset (&caught_signals, handled_sig[i]); + } + + act.sa_handler = abort_gzip_signal; + act.sa_mask = caught_signals; + act.sa_flags = 0; + + for (i = 0; i < nsigs; i++) + if (sigismember (&caught_signals, handled_sig[i])) + { + if (i == 0) + foreground = 1; + sigaction (handled_sig[i], &act, NULL); + } +} + +/* ======================================================================== + * Free all dynamically allocated variables and exit with the given code. + */ +local void do_exit(exitcode) + int exitcode; +{ + static int in_exit = 0; + + if (in_exit) exit(exitcode); + in_exit = 1; + free(env); + env = NULL; + FREE(inbuf); + FREE(outbuf); + FREE(d_buf); + FREE(window); +#ifndef MAXSEG_64K + FREE(tab_prefix); +#else + FREE(tab_prefix0); + FREE(tab_prefix1); +#endif + exit(exitcode); +} + +static void +finish_out (void) +{ + if (fclose (stdout) != 0) + write_error (); + do_exit (OK); +} + +/* ======================================================================== + * Close and unlink the output file. + */ +static void +remove_output_file (bool signals_already_blocked) +{ + int fd; + sigset_t oldset; + + if (!signals_already_blocked) + sigprocmask (SIG_BLOCK, &caught_signals, &oldset); + fd = remove_ofname_fd; + if (0 <= fd) + { + char fname[MAX_PATH_LEN]; + remove_ofname_fd = -1; + close (fd); + volatile_strcpy (fname, remove_ofname); + xunlink (ofname); + } + if (!signals_already_blocked) + sigprocmask (SIG_SETMASK, &oldset, NULL); +} + +/* ======================================================================== + * Error handler. + */ +void +abort_gzip (void) +{ + remove_output_file (false); + do_exit(ERROR); +} + +/* ======================================================================== + * Signal handler. + */ +static void +abort_gzip_signal (int sig) +{ + remove_output_file (true); + if (sig == exiting_signal) + _exit (WARNING); + signal (sig, SIG_DFL); + raise (sig); +} diff --git a/src/main/resource/testFiles/gzip/revFiles/051ed8_8b83dc_gzip.c b/src/main/resource/testFiles/gzip/revFiles/051ed8_8b83dc_gzip.c new file mode 100644 index 0000000..e6a7761 --- /dev/null +++ b/src/main/resource/testFiles/gzip/revFiles/051ed8_8b83dc_gzip.c @@ -0,0 +1,2165 @@ +/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + + Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2018 Free Software + Foundation, Inc. + Copyright (C) 1992-1993 Jean-loup Gailly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* + * The unzip code was written and put in the public domain by Mark Adler. + * Portions of the lzw code are derived from the public domain 'compress' + * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, + * Ken Turkowski, Dave Mack and Peter Jannesen. + * + * See the license_msg below and the file COPYING for the software license. + * See the file algorithm.doc for the compression algorithms and file formats. + */ + +static char const *const license_msg[] = { +"Copyright (C) 2018 Free Software Foundation, Inc.", +"Copyright (C) 1993 Jean-loup Gailly.", +"This is free software. You may redistribute copies of it under the terms of", +"the GNU General Public License .", +"There is NO WARRANTY, to the extent permitted by law.", +0}; + +/* Compress files with zip algorithm and 'compress' interface. + * See help() function below for all options. + * Outputs: + * file.gz: compressed file with same mode, owner, and utimes + * or stdout with -c option or if stdin used as input. + * If the output file name had to be truncated, the original name is kept + * in the compressed file. + * On MSDOS, file.tmp -> file.tmz. + * + * Using gz on MSDOS would create too many file name conflicts. For + * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for + * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz. + * I also considered 12345678.txt -> 12345txt.gz but this truncates the name + * too heavily. There is no ideal solution given the MSDOS 8+3 limitation. + * + * For the meaning of all compilation flags, see comments in Makefile.in. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tailor.h" +#include "gzip.h" +#include "intprops.h" +#include "lzw.h" +#include "revision.h" +#include "timespec.h" + +#include "dirname.h" +#include "dosname.h" +#include "fcntl--.h" +#include "getopt.h" +#include "ignore-value.h" +#include "stat-time.h" +#include "version.h" +#include "xalloc.h" +#include "yesno.h" + + /* configuration */ + +#include +#include +#include +#include + +#ifndef NO_DIR +# define NO_DIR 0 +#endif +#if !NO_DIR +# include +# include +#endif + +#ifndef NO_UTIME +# include +#endif + +#ifndef MAX_PATH_LEN +# define MAX_PATH_LEN 1024 /* max pathname length */ +#endif + +#ifndef SEEK_END +# define SEEK_END 2 +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +#ifdef off_t + off_t lseek (int fd, off_t offset, int whence); +#endif + +#ifndef OFF_T_MAX +# define OFF_T_MAX TYPE_MAXIMUM (off_t) +#endif + +#ifndef HAVE_WORKING_O_NOFOLLOW +# define HAVE_WORKING_O_NOFOLLOW 0 +#endif + +/* Separator for file name parts (see shorten_name()) */ +#ifdef NO_MULTIPLE_DOTS +# define PART_SEP "-" +#else +# define PART_SEP "." +#endif + + /* global buffers */ + +DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA); +DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); +DECLARE(ush, d_buf, DIST_BUFSIZE); +DECLARE(uch, window, 2L*WSIZE); +#ifndef MAXSEG_64K + DECLARE(ush, tab_prefix, 1L<.", + 0}; + char const *const *p = help_msg; + + printf ("Usage: %s [OPTION]... [FILE]...\n", program_name); + while (*p) printf ("%s\n", *p++); +} + +/* ======================================================================== */ +local void license() +{ + char const *const *p = license_msg; + + printf ("%s %s\n", program_name, Version); + while (*p) printf ("%s\n", *p++); +} + +/* ======================================================================== */ +local void version() +{ + license (); + printf ("\n"); + printf ("Written by Jean-loup Gailly.\n"); +} + +local void progerror (char const *string) +{ + int e = errno; + fprintf (stderr, "%s: ", program_name); + errno = e; + perror(string); + exit_code = ERROR; +} + +/* ======================================================================== */ +int main (int argc, char **argv) +{ + int file_count; /* number of files to process */ + size_t proglen; /* length of program_name */ + char **argv_copy; + int env_argc; + char **env_argv; + + EXPAND(argc, argv); /* wild card expansion if necessary */ + + program_name = gzip_base_name (argv[0]); + proglen = strlen (program_name); + + /* Suppress .exe for MSDOS and OS/2: */ + if (4 < proglen && strequ (program_name + proglen - 4, ".exe")) + program_name[proglen - 4] = '\0'; + + /* Add options in GZIP environment variable if there is one */ + argv_copy = argv; + env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR); + env_argv = env ? argv_copy : NULL; + +#ifndef GNU_STANDARD +# define GNU_STANDARD 1 +#endif +#if !GNU_STANDARD + /* For compatibility with old compress, use program name as an option. + * Unless you compile with -DGNU_STANDARD=0, this program will behave as + * gzip even if it is invoked under the name gunzip or zcat. + * + * Systems which do not support links can still use -d or -dc. + * Ignore an .exe extension for MSDOS and OS/2. + */ + if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */ + || strncmp (program_name, "gun", 3) == 0) /* gunzip */ + decompress = 1; + else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */ + || strequ (program_name, "gzcat")) /* gzcat */ + decompress = to_stdout = 1; +#endif + + z_suffix = Z_SUFFIX; + z_len = strlen(z_suffix); + + while (true) { + int optc; + int longind = -1; + + if (env_argv) + { + if (env_argv[optind] && strequ (env_argv[optind], "--")) + optc = ENV_OPTION + '-'; + else + { + optc = getopt_long (env_argc, env_argv, shortopts, longopts, + &longind); + if (0 <= optc) + optc += ENV_OPTION; + else + { + if (optind != env_argc) + { + fprintf (stderr, + ("%s: %s: non-option in "OPTIONS_VAR + " environment variable\n"), + program_name, env_argv[optind]); + try_help (); + } + + /* Wait until here before warning, so that GZIP='-q' + doesn't warn. */ + if (env_argc != 1 && !quiet) + fprintf (stderr, + ("%s: warning: "OPTIONS_VAR" environment variable" + " is deprecated; use an alias or script\n"), + program_name); + + /* Start processing ARGC and ARGV instead. */ + free (env_argv); + env_argv = NULL; + optind = 1; + longind = -1; + } + } + } + + if (!env_argv) + optc = getopt_long (argc, argv, shortopts, longopts, &longind); + if (optc < 0) + break; + + switch (optc) { + case 'a': + ascii = 1; break; + case 'b': + maxbits = atoi(optarg); + for (; *optarg; optarg++) + if (! ('0' <= *optarg && *optarg <= '9')) + { + fprintf (stderr, "%s: -b operand is not an integer\n", + program_name); + try_help (); + } + break; + case 'c': + to_stdout = 1; break; + case 'd': + decompress = 1; break; + case 'f': + force++; break; + case 'h': case 'H': + help (); finish_out (); break; + case 'k': + keep = 1; break; + case 'l': + list = decompress = to_stdout = 1; break; + case 'L': + license (); finish_out (); break; + case 'm': /* undocumented, may change later */ + no_time = 1; break; + case 'M': /* undocumented, may change later */ + no_time = 0; break; + case 'n': + case 'n' + ENV_OPTION: + no_name = no_time = 1; break; + case 'N': + case 'N' + ENV_OPTION: + no_name = no_time = 0; break; + case PRESUME_INPUT_TTY_OPTION: + presume_input_tty = true; break; + case 'q': + case 'q' + ENV_OPTION: + quiet = 1; verbose = 0; break; + case 'r': +#if NO_DIR + fprintf (stderr, "%s: -r not supported on this system\n", + program_name); + try_help (); +#else + recursive = 1; +#endif + break; + + case RSYNCABLE_OPTION: + case RSYNCABLE_OPTION + ENV_OPTION: + rsync = 1; + break; + case 'S': +#ifdef NO_MULTIPLE_DOTS + if (*optarg == '.') optarg++; +#endif + z_len = strlen(optarg); + z_suffix = optarg; + break; + case SYNCHRONOUS_OPTION: + synchronous = true; + break; + case 't': + test = decompress = to_stdout = 1; + break; + case 'v': + case 'v' + ENV_OPTION: + verbose++; quiet = 0; break; + case 'V': + version (); finish_out (); break; + case 'Z': +#ifdef LZW + do_lzw = 1; break; +#else + fprintf(stderr, "%s: -Z not supported in this version\n", + program_name); + try_help (); + break; +#endif + case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION: + case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION: + case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION: + optc -= ENV_OPTION; + FALLTHROUGH; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + level = optc - '0'; + break; + + default: + if (ENV_OPTION <= optc && optc != ENV_OPTION + '?') + { + /* Output a diagnostic, since getopt_long didn't. */ + fprintf (stderr, "%s: ", program_name); + if (longind < 0) + fprintf (stderr, "-%c: ", optc - ENV_OPTION); + else + fprintf (stderr, "--%s: ", longopts[longind].name); + fprintf (stderr, ("option not valid in "OPTIONS_VAR + " environment variable\n")); + } + try_help (); + } + } /* loop on all arguments */ + + /* By default, save name and timestamp on compression but do not + * restore them on decompression. + */ + if (no_time < 0) no_time = decompress; + if (no_name < 0) no_name = decompress; + + file_count = argc - optind; + +#if O_BINARY +#else + if (ascii && !quiet) { + fprintf(stderr, "%s: option --ascii ignored on this system\n", + program_name); + } +#endif + if (z_len == 0 || z_len > MAX_SUFFIX) { + fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix); + do_exit(ERROR); + } + + if (do_lzw && !decompress) work = lzw; + + /* Allocate all global buffers (for DYN_ALLOC option) */ + ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA); + ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); + ALLOC(ush, d_buf, DIST_BUFSIZE); + ALLOC(uch, window, 2L*WSIZE); +#ifndef MAXSEG_64K + ALLOC(ush, tab_prefix, 1L< s && ! ISSLASH (suffix[slen - s - 1]) + && strequ(suffix + slen - s, *suf)) { + match = name+nlen-s; + break; + } + } while (*++suf != NULL); + free(z_lower); + + return match; +} + + +/* Open file NAME with the given flags and store its status + into *ST. Return a file descriptor to the newly opened file, or -1 + (setting errno) on failure. */ +static int +open_and_stat (char *name, int flags, struct stat *st) +{ + int fd; + int atfd = AT_FDCWD; + char const *base = name; + + /* Refuse to follow symbolic links unless -c or -f. */ + if (!to_stdout && !force) + { + if (HAVE_WORKING_O_NOFOLLOW) + flags |= O_NOFOLLOW; + else + { +#ifdef S_ISLNK + if (lstat (name, st) != 0) + return -1; + else if (S_ISLNK (st->st_mode)) + { + errno = ELOOP; + return -1; + } +#endif + } + } + + if (!keep) + { + char const *b = last_component (name); + int f = atdir_set (name, b - name); + if (0 <= f) + { + base = b; + atfd = f; + } + } + + fd = openat (atfd, base, flags); + if (0 <= fd && fstat (fd, st) != 0) + { + int e = errno; + close (fd); + errno = e; + return -1; + } + return fd; +} + + +/* ======================================================================== + * Set ifname to the input file name (with a suffix appended if necessary) + * and istat to its stats. For decompression, if no file exists with the + * original name, try adding successively z_suffix, .gz, .z, -z and .Z. + * For MSDOS, we try only z_suffix and z. + * Return an open file descriptor or -1. + */ +static int +open_input_file (iname, sbuf) + char *iname; + struct stat *sbuf; +{ + int ilen; /* strlen(ifname) */ + int z_suffix_errno = 0; + static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL}; + char const **suf = suffixes; + char const *s; +#ifdef NO_MULTIPLE_DOTS + char *dot; /* pointer to ifname extension, or NULL */ +#endif + int fd; + int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY + | (ascii && !decompress ? 0 : O_BINARY)); + + *suf = z_suffix; + + if (sizeof ifname - 1 <= strlen (iname)) + goto name_too_long; + + strcpy(ifname, iname); + + /* If input file exists, return OK. */ + fd = open_and_stat (ifname, open_flags, sbuf); + if (0 <= fd) + return fd; + + if (!decompress || errno != ENOENT) { + progerror(ifname); + return -1; + } + /* File.ext doesn't exist. Try adding a suffix. */ + s = get_suffix(ifname); + if (s != NULL) { + progerror(ifname); /* ifname already has z suffix and does not exist */ + return -1; + } +#ifdef NO_MULTIPLE_DOTS + dot = strrchr(ifname, '.'); + if (dot == NULL) { + strcat(ifname, "."); + dot = strrchr(ifname, '.'); + } +#endif + ilen = strlen(ifname); + if (strequ(z_suffix, ".gz")) suf++; + + /* Search for all suffixes */ + do { + char const *s0 = s = *suf; + strcpy (ifname, iname); +#ifdef NO_MULTIPLE_DOTS + if (*s == '.') s++; + if (*dot == '\0') strcpy (dot, "."); +#endif +#ifdef MAX_EXT_CHARS + if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1)) + dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0'; +#endif + if (sizeof ifname <= ilen + strlen (s)) + goto name_too_long; + strcat(ifname, s); + fd = open_and_stat (ifname, open_flags, sbuf); + if (0 <= fd) + return fd; + if (errno != ENOENT) + { + progerror (ifname); + return -1; + } + if (strequ (s0, z_suffix)) + z_suffix_errno = errno; + } while (*++suf != NULL); + + /* No suffix found, complain using z_suffix: */ + strcpy(ifname, iname); +#ifdef NO_MULTIPLE_DOTS + if (*dot == '\0') strcpy(dot, "."); +#endif +#ifdef MAX_EXT_CHARS + if (MAX_EXT_CHARS < z_len + strlen (dot + 1)) + dot[MAX_EXT_CHARS + 1 - z_len] = '\0'; +#endif + strcat(ifname, z_suffix); + errno = z_suffix_errno; + progerror(ifname); + return -1; + + name_too_long: + fprintf (stderr, "%s: %s: file name too long\n", program_name, iname); + exit_code = ERROR; + return -1; +} + +/* ======================================================================== + * Generate ofname given ifname. Return OK, or WARNING if file must be skipped. + * Sets save_orig_name to true if the file name has been truncated. + */ +local int make_ofname() +{ + char *suff; /* ofname z suffix */ + + strcpy(ofname, ifname); + /* strip a version number if any and get the gzip suffix if present: */ + suff = get_suffix(ofname); + + if (decompress) { + if (suff == NULL) { + /* With -t or -l, try all files (even without .gz suffix) + * except with -r (behave as with just -dr). + */ + if (!recursive && (list || test)) return OK; + + /* Avoid annoying messages with -r */ + if (verbose || (!recursive && !quiet)) { + WARN((stderr,"%s: %s: unknown suffix -- ignored\n", + program_name, ifname)); + } + return WARNING; + } + /* Make a special case for .tgz and .taz: */ + strlwr(suff); + if (strequ(suff, ".tgz") || strequ(suff, ".taz")) { + strcpy(suff, ".tar"); + } else { + *suff = '\0'; /* strip the z suffix */ + } + /* ofname might be changed later if infile contains an original name */ + + } else if (suff && ! force) { + /* Avoid annoying messages with -r (see treat_dir()) */ + if (verbose || (!recursive && !quiet)) { + /* Don't use WARN, as it affects exit status. */ + fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n", + program_name, ifname, suff); + } + return WARNING; + } else { + save_orig_name = 0; + +#ifdef NO_MULTIPLE_DOTS + suff = strrchr(ofname, '.'); + if (suff == NULL) { + if (sizeof ofname <= strlen (ofname) + 1) + goto name_too_long; + strcat(ofname, "."); +# ifdef MAX_EXT_CHARS + if (strequ(z_suffix, "z")) { + if (sizeof ofname <= strlen (ofname) + 2) + goto name_too_long; + strcat(ofname, "gz"); /* enough room */ + return OK; + } + /* On the Atari and some versions of MSDOS, + * ENAMETOOLONG does not work correctly. So we + * must truncate here. + */ + } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) { + suff[MAX_SUFFIX+1-z_len] = '\0'; + save_orig_name = 1; +# endif + } +#endif /* NO_MULTIPLE_DOTS */ + if (sizeof ofname <= strlen (ofname) + z_len) + goto name_too_long; + strcat(ofname, z_suffix); + + } /* decompress ? */ + return OK; + + name_too_long: + WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname)); + return WARNING; +} + +/* Discard NBYTES input bytes from the input, or up through the next + zero byte if NBYTES == (size_t) -1. If FLAGS say that the header + CRC should be computed, update the CRC accordingly. */ +static void +discard_input_bytes (nbytes, flags) + size_t nbytes; + unsigned int flags; +{ + while (nbytes != 0) + { + uch c = get_byte (); + if (flags & HEADER_CRC) + updcrc (&c, 1); + if (nbytes != (size_t) -1) + nbytes--; + else if (! c) + break; + } +} + +/* ======================================================================== + * Check the magic number of the input file and update ofname if an + * original name was given and to_stdout is not set. + * Return the compression method, -1 for error, -2 for warning. + * Set inptr to the offset of the next byte to be processed. + * Updates time_stamp if there is one and neither -m nor -n is used. + * This function may be called repeatedly for an input file consisting + * of several contiguous gzip'ed members. + * IN assertions: there is at least one remaining compressed member. + * If the member is a zip file, it must be the only one. + */ +local int get_method(in) + int in; /* input file descriptor */ +{ + uch flags; /* compression flags */ + uch magic[10]; /* magic header */ + int imagic0; /* first magic byte or EOF */ + int imagic1; /* like magic[1], but can represent EOF */ + ulg stamp; /* timestamp */ + + /* If --force and --stdout, zcat == cat, so do not complain about + * premature end of file: use try_byte instead of get_byte. + */ + if (force && to_stdout) { + imagic0 = try_byte(); + magic[0] = imagic0; + imagic1 = try_byte (); + magic[1] = imagic1; + /* If try_byte returned EOF, magic[1] == (char) EOF. */ + } else { + magic[0] = get_byte (); + imagic0 = 0; + if (magic[0]) { + magic[1] = get_byte (); + imagic1 = 0; /* avoid lint warning */ + } else { + imagic1 = try_byte (); + magic[1] = imagic1; + } + } + method = -1; /* unknown yet */ + part_nb++; /* number of parts in gzip file */ + header_bytes = 0; + last_member = 0; + /* assume multiple members in gzip file except for record oriented I/O */ + + if (memcmp(magic, GZIP_MAGIC, 2) == 0 + || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) { + + method = (int)get_byte(); + if (method != DEFLATED) { + fprintf(stderr, + "%s: %s: unknown method %d -- not supported\n", + program_name, ifname, method); + exit_code = ERROR; + return -1; + } + work = unzip; + flags = (uch)get_byte(); + + if ((flags & ENCRYPTED) != 0) { + fprintf(stderr, + "%s: %s is encrypted -- not supported\n", + program_name, ifname); + exit_code = ERROR; + return -1; + } + if ((flags & RESERVED) != 0) { + fprintf(stderr, + "%s: %s has flags 0x%x -- not supported\n", + program_name, ifname, flags); + exit_code = ERROR; + if (force <= 1) return -1; + } + stamp = (ulg)get_byte(); + stamp |= ((ulg)get_byte()) << 8; + stamp |= ((ulg)get_byte()) << 16; + stamp |= ((ulg)get_byte()) << 24; + if (stamp != 0 && !no_time) + { + if (stamp <= TYPE_MAXIMUM (time_t)) + { + time_stamp.tv_sec = stamp; + time_stamp.tv_nsec = 0; + } + else + { + WARN ((stderr, + "%s: %s: MTIME %lu out of range for this platform\n", + program_name, ifname, stamp)); + time_stamp.tv_sec = TYPE_MAXIMUM (time_t); + time_stamp.tv_nsec = TIMESPEC_RESOLUTION - 1; + } + } + + magic[8] = get_byte (); /* Ignore extra flags. */ + magic[9] = get_byte (); /* Ignore OS type. */ + + if (flags & HEADER_CRC) + { + magic[2] = DEFLATED; + magic[3] = flags; + magic[4] = stamp & 0xff; + magic[5] = (stamp >> 8) & 0xff; + magic[6] = (stamp >> 16) & 0xff; + magic[7] = stamp >> 24; + updcrc (NULL, 0); + updcrc (magic, 10); + } + + if ((flags & EXTRA_FIELD) != 0) { + uch lenbuf[2]; + unsigned int len = lenbuf[0] = get_byte (); + len |= (lenbuf[1] = get_byte ()) << 8; + if (verbose) { + fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n", + program_name, ifname, len); + } + if (flags & HEADER_CRC) + updcrc (lenbuf, 2); + discard_input_bytes (len, flags); + } + + /* Get original file name if it was truncated */ + if ((flags & ORIG_NAME) != 0) { + if (no_name || (to_stdout && !list) || part_nb > 1) { + /* Discard the old name */ + discard_input_bytes (-1, flags); + } else { + /* Copy the base name. Keep a directory prefix intact. */ + char *p = gzip_base_name (ofname); + char *base = p; + for (;;) { + *p = (char) get_byte (); + if (*p++ == '\0') break; + if (p >= ofname+sizeof(ofname)) { + gzip_error ("corrupted input -- file name too large"); + } + } + if (flags & HEADER_CRC) + updcrc ((uch *) base, p - base); + p = gzip_base_name (base); + memmove (base, p, strlen (p) + 1); + /* If necessary, adapt the name to local OS conventions: */ + if (!list) { + MAKE_LEGAL_NAME(base); + if (base) list=0; /* avoid warning about unused variable */ + } + } /* no_name || to_stdout */ + } /* ORIG_NAME */ + + /* Discard file comment if any */ + if ((flags & COMMENT) != 0) { + discard_input_bytes (-1, flags); + } + + if (flags & HEADER_CRC) + { + unsigned int crc16 = updcrc (magic, 0) & 0xffff; + unsigned int header16 = get_byte (); + header16 |= ((unsigned int) get_byte ()) << 8; + if (header16 != crc16) + { + fprintf (stderr, + "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n", + program_name, ifname, header16, crc16); + exit_code = ERROR; + if (force <= 1) + return -1; + } + } + + if (part_nb == 1) { + header_bytes = inptr + 2*4; /* include crc and size */ + } + + } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2 + && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) { + /* To simplify the code, we support a zip file when alone only. + * We are thus guaranteed that the entire local header fits in inbuf. + */ + inptr = 0; + work = unzip; + if (check_zipfile(in) != OK) return -1; + /* check_zipfile may get ofname from the local header */ + last_member = 1; + + } else if (memcmp(magic, PACK_MAGIC, 2) == 0) { + work = unpack; + method = PACKED; + + } else if (memcmp(magic, LZW_MAGIC, 2) == 0) { + work = unlzw; + method = COMPRESSED; + last_member = 1; + + } else if (memcmp(magic, LZH_MAGIC, 2) == 0) { + work = unlzh; + method = LZHED; + last_member = 1; + + } else if (force && to_stdout && !list) { /* pass input unchanged */ + method = STORED; + work = copy; + if (imagic1 != EOF) + inptr--; + last_member = 1; + if (imagic0 != EOF) { + write_buf (STDOUT_FILENO, magic, 1); + bytes_out++; + } + } + if (method >= 0) return method; + + if (part_nb == 1) { + fprintf (stderr, "\n%s: %s: not in gzip format\n", + program_name, ifname); + exit_code = ERROR; + return -1; + } else { + if (magic[0] == 0) + { + int inbyte; + for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ()) + continue; + if (inbyte == EOF) + { + if (verbose) + WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n", + program_name, ifname)); + return -3; + } + } + + WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n", + program_name, ifname)); + return -2; + } +} + +/* ======================================================================== + * Display the characteristics of the compressed file. + * If the given method is < 0, display the accumulated totals. + * IN assertions: time_stamp, header_bytes and ifile_size are initialized. + */ +local void do_list(ifd, method) + int ifd; /* input file descriptor */ + int method; /* compression method */ +{ + ulg crc; /* original crc */ + static int first_time = 1; + static char const *const methods[MAX_METHODS] = { + "store", /* 0 */ + "compr", /* 1 */ + "pack ", /* 2 */ + "lzh ", /* 3 */ + "", "", "", "", /* 4 to 7 reserved */ + "defla"}; /* 8 */ + int positive_off_t_width = 1; + off_t o; + + for (o = OFF_T_MAX; 9 < o; o /= 10) { + positive_off_t_width++; + } + + if (first_time && method >= 0) { + first_time = 0; + if (verbose) { + printf("method crc date time "); + } + if (!quiet) { + printf("%*.*s %*.*s ratio uncompressed_name\n", + positive_off_t_width, positive_off_t_width, "compressed", + positive_off_t_width, positive_off_t_width, "uncompressed"); + } + } else if (method < 0) { + if (total_in <= 0 || total_out <= 0) return; + if (verbose) { + printf(" "); + } + if (verbose || !quiet) { + fprint_off(stdout, total_in, positive_off_t_width); + printf(" "); + fprint_off(stdout, total_out, positive_off_t_width); + printf(" "); + } + display_ratio(total_out-(total_in-header_bytes), total_out, stdout); + /* header_bytes is not meaningful but used to ensure the same + * ratio if there is a single file. + */ + printf(" (totals)\n"); + return; + } + crc = (ulg)~0; /* unknown */ + bytes_out = -1L; + bytes_in = ifile_size; + + if (method == DEFLATED && !last_member) { + /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files. + * If the lseek fails, we could use read() to get to the end, but + * --list is used to get quick results. + * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if + * you are not concerned about speed. + */ + bytes_in = lseek(ifd, (off_t)(-8), SEEK_END); + if (bytes_in != -1L) { + uch buf[8]; + bytes_in += 8L; + if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) { + read_error(); + } + crc = LG(buf); + bytes_out = LG(buf+4); + } + } + + if (verbose) + { + static char const month_abbr[][4] + = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + struct tm *tm = localtime (&time_stamp.tv_sec); + printf ("%5s %08lx ", methods[method], crc); + if (tm) + printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon], + tm->tm_mday, tm->tm_hour, tm->tm_min); + else + printf ("??? ?? ??:?? "); + } + fprint_off(stdout, bytes_in, positive_off_t_width); + printf(" "); + fprint_off(stdout, bytes_out, positive_off_t_width); + printf(" "); + if (bytes_in == -1L) { + total_in = -1L; + bytes_in = bytes_out = header_bytes = 0; + } else if (total_in >= 0) { + total_in += bytes_in; + } + if (bytes_out == -1L) { + total_out = -1L; + bytes_in = bytes_out = header_bytes = 0; + } else if (total_out >= 0) { + total_out += bytes_out; + } + display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout); + printf(" %s\n", ofname); +} + +/* ======================================================================== + * Shorten the given name by one character, or replace a .tar extension + * with .tgz. Truncate the last part of the name which is longer than + * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name + * has only parts shorter than MIN_PART truncate the longest part. + * For decompression, just remove the last character of the name. + * + * IN assertion: for compression, the suffix of the given name is z_suffix. + */ +local void shorten_name(name) + char *name; +{ + int len; /* length of name without z_suffix */ + char *trunc = NULL; /* character to be truncated */ + int plen; /* current part length */ + int min_part = MIN_PART; /* current minimum part length */ + char *p; + + len = strlen(name); + if (decompress) { + if (len <= 1) + gzip_error ("name too short"); + name[len-1] = '\0'; + return; + } + p = get_suffix(name); + if (! p) + gzip_error ("can't recover suffix\n"); + *p = '\0'; + save_orig_name = 1; + + /* compress 1234567890.tar to 1234567890.tgz */ + if (len > 4 && strequ(p-4, ".tar")) { + strcpy(p-4, ".tgz"); + return; + } + /* Try keeping short extensions intact: + * 1234.678.012.gz -> 123.678.012.gz + */ + do { + p = last_component (name); + while (*p) { + plen = strcspn(p, PART_SEP); + p += plen; + if (plen > min_part) trunc = p-1; + if (*p) p++; + } + } while (trunc == NULL && --min_part != 0); + + if (trunc != NULL) { + do { + trunc[0] = trunc[1]; + } while (*trunc++); + trunc--; + } else { + trunc = strrchr(name, PART_SEP[0]); + if (!trunc) + gzip_error ("internal error in shorten_name"); + if (trunc[1] == '\0') trunc--; /* force truncation */ + } + strcpy(trunc, z_suffix); +} + +/* ======================================================================== + * The compressed file already exists, so ask for confirmation. + * Return ERROR if the file must be skipped. + */ +local int check_ofname() +{ + /* Ask permission to overwrite the existing file */ + if (!force) { + int ok = 0; + fprintf (stderr, "%s: %s already exists;", program_name, ofname); + if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) { + fprintf(stderr, " do you wish to overwrite (y or n)? "); + fflush(stderr); + ok = yesno(); + } + if (!ok) { + fprintf(stderr, "\tnot overwritten\n"); + if (exit_code == OK) exit_code = WARNING; + return ERROR; + } + } + if (xunlink (ofname)) { + progerror(ofname); + return ERROR; + } + return OK; +} + +/* Change the owner and group of a file. FD is a file descriptor for + the file and NAME its name. Change it to user UID and to group GID. + If UID or GID is -1, though, do not change the corresponding user + or group. */ +#if ! (HAVE_FCHOWN || HAVE_CHOWN) +/* The types uid_t and gid_t do not exist on mingw, so don't assume them. */ +# define do_chown(fd, name, uid, gid) ((void) 0) +#else +static void +do_chown (int fd, char const *name, uid_t uid, gid_t gid) +{ +# if HAVE_FCHOWN + ignore_value (fchown (fd, uid, gid)); +# else + ignore_value (chown (name, uid, gid)); +# endif +} +#endif + +/* ======================================================================== + * Copy modes, times, ownership from input file to output file. + * IN assertion: to_stdout is false. + */ +local void copy_stat(ifstat) + struct stat *ifstat; +{ + mode_t mode = ifstat->st_mode & S_IRWXUGO; + int r; + +#ifndef NO_UTIME + bool restoring; + struct timespec timespec[2]; + timespec[0] = get_stat_atime (ifstat); + timespec[1] = get_stat_mtime (ifstat); + restoring = (decompress && 0 <= time_stamp.tv_nsec + && ! (timespec[1].tv_sec == time_stamp.tv_sec + && timespec[1].tv_nsec == time_stamp.tv_nsec)); + if (restoring) + timespec[1] = time_stamp; + + if (fdutimens (ofd, ofname, timespec) == 0) + { + if (restoring && 1 < verbose) { + fprintf(stderr, "%s: timestamp restored\n", ofname); + } + } + else + { + int e = errno; + WARN ((stderr, "%s: ", program_name)); + if (!quiet) + { + errno = e; + perror (ofname); + } + } +#endif + + /* Change the group first, then the permissions, then the owner. + That way, the permissions will be correct on systems that allow + users to give away files, without introducing a security hole. + Security depends on permissions not containing the setuid or + setgid bits. */ + + do_chown (ofd, ofname, -1, ifstat->st_gid); + +#if HAVE_FCHMOD + r = fchmod (ofd, mode); +#else + r = chmod (ofname, mode); +#endif + if (r != 0) { + int e = errno; + WARN ((stderr, "%s: ", program_name)); + if (!quiet) { + errno = e; + perror(ofname); + } + } + + do_chown (ofd, ofname, ifstat->st_uid, -1); +} + +#if ! NO_DIR + +/* ======================================================================== + * Recurse through the given directory. + */ +local void treat_dir (fd, dir) + int fd; + char *dir; +{ + DIR *dirp; + char nbuf[MAX_PATH_LEN]; + char *entries; + char const *entry; + size_t entrylen; + + dirp = fdopendir (fd); + + if (dirp == NULL) { + progerror(dir); + close (fd); + return ; + } + + entries = streamsavedir (dirp, SAVEDIR_SORT_NONE); + if (! entries) + progerror (dir); + if (closedir (dirp) != 0) + progerror (dir); + if (! entries) + return; + + for (entry = entries; *entry; entry += entrylen + 1) { + size_t len = strlen (dir); + entrylen = strlen (entry); + if (strequ (entry, ".") || strequ (entry, "..")) + continue; + if (len + entrylen < MAX_PATH_LEN - 2) { + strcpy(nbuf,dir); + if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1])) + nbuf[len++] = '/'; + strcpy (nbuf + len, entry); + treat_file(nbuf); + } else { + fprintf(stderr,"%s: %s/%s: pathname too long\n", + program_name, dir, entry); + exit_code = ERROR; + } + } + free (entries); +} +#endif /* ! NO_DIR */ + +/* Make sure signals get handled properly. */ + +static void +install_signal_handlers () +{ + int nsigs = sizeof handled_sig / sizeof handled_sig[0]; + int i; + struct sigaction act; + + sigemptyset (&caught_signals); + for (i = 0; i < nsigs; i++) + { + sigaction (handled_sig[i], NULL, &act); + if (act.sa_handler != SIG_IGN) + sigaddset (&caught_signals, handled_sig[i]); + } + + act.sa_handler = abort_gzip_signal; + act.sa_mask = caught_signals; + act.sa_flags = 0; + + for (i = 0; i < nsigs; i++) + if (sigismember (&caught_signals, handled_sig[i])) + { + if (i == 0) + foreground = 1; + sigaction (handled_sig[i], &act, NULL); + } +} + +/* ======================================================================== + * Free all dynamically allocated variables and exit with the given code. + */ +local void do_exit(exitcode) + int exitcode; +{ + static int in_exit = 0; + + if (in_exit) exit(exitcode); + in_exit = 1; + free(env); + env = NULL; + FREE(inbuf); + FREE(outbuf); + FREE(d_buf); + FREE(window); +#ifndef MAXSEG_64K + FREE(tab_prefix); +#else + FREE(tab_prefix0); + FREE(tab_prefix1); +#endif + exit(exitcode); +} + +static void +finish_out (void) +{ + if (fclose (stdout) != 0) + write_error (); + do_exit (OK); +} + +/* ======================================================================== + * Close and unlink the output file. + */ +static void +remove_output_file (bool signals_already_blocked) +{ + int fd; + sigset_t oldset; + + if (!signals_already_blocked) + sigprocmask (SIG_BLOCK, &caught_signals, &oldset); + fd = remove_ofname_fd; + if (0 <= fd) + { + char fname[MAX_PATH_LEN]; + remove_ofname_fd = -1; + close (fd); + volatile_strcpy (fname, remove_ofname); + xunlink (fname); + } + if (!signals_already_blocked) + sigprocmask (SIG_SETMASK, &oldset, NULL); +} + +/* ======================================================================== + * Error handler. + */ +void +abort_gzip (void) +{ + remove_output_file (false); + do_exit(ERROR); +} + +/* ======================================================================== + * Signal handler. + */ +static void +abort_gzip_signal (int sig) +{ + remove_output_file (true); + if (sig == exiting_signal) + _exit (WARNING); + signal (sig, SIG_DFL); + raise (sig); +} diff --git a/src/main/resource/testFiles/php-src/prevFiles/prev_e76cf8_39753f_Zend#zend.c b/src/main/resource/testFiles/php-src/prevFiles/prev_e76cf8_39753f_Zend#zend.c new file mode 100644 index 0000000..f262f8b --- /dev/null +++ b/src/main/resource/testFiles/php-src/prevFiles/prev_e76cf8_39753f_Zend#zend.c @@ -0,0 +1,1472 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Andi Gutmans | + | Zeev Suraski | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "zend.h" +#include "zend_extensions.h" +#include "zend_modules.h" +#include "zend_constants.h" +#include "zend_list.h" +#include "zend_API.h" +#include "zend_exceptions.h" +#include "zend_builtin_functions.h" +#include "zend_ini.h" +#include "zend_vm.h" +#include "zend_dtrace.h" +#include "zend_virtual_cwd.h" + +#ifdef ZTS +# define GLOBAL_FUNCTION_TABLE global_function_table +# define GLOBAL_CLASS_TABLE global_class_table +# define GLOBAL_CONSTANTS_TABLE global_constants_table +# define GLOBAL_AUTO_GLOBALS_TABLE global_auto_globals_table +#else +# define GLOBAL_FUNCTION_TABLE CG(function_table) +# define GLOBAL_CLASS_TABLE CG(class_table) +# define GLOBAL_AUTO_GLOBALS_TABLE CG(auto_globals) +# define GLOBAL_CONSTANTS_TABLE EG(zend_constants) +#endif + +/* true multithread-shared globals */ +ZEND_API zend_class_entry *zend_standard_class_def = NULL; +ZEND_API size_t (*zend_printf)(const char *format, ...); +ZEND_API zend_write_func_t zend_write; +ZEND_API FILE *(*zend_fopen)(const char *filename, zend_string **opened_path); +ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle); +ZEND_API void (*zend_block_interruptions)(void); +ZEND_API void (*zend_unblock_interruptions)(void); +ZEND_API void (*zend_ticks_function)(int ticks); +ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); +size_t (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); +zend_string *(*zend_vstrpprintf)(size_t max_len, const char *format, va_list ap); +ZEND_API char *(*zend_getenv)(char *name, size_t name_len); +ZEND_API zend_string *(*zend_resolve_path)(const char *filename, int filename_len); + +void (*zend_on_timeout)(int seconds); + +static void (*zend_message_dispatcher_p)(zend_long message, const void *data); +static zval *(*zend_get_configuration_directive_p)(zend_string *name); + +static ZEND_INI_MH(OnUpdateErrorReporting) /* {{{ */ +{ + if (!new_value) { + EG(error_reporting) = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED; + } else { + EG(error_reporting) = atoi(new_value->val); + } + return SUCCESS; +} +/* }}} */ + +static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */ +{ + OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); + + if (GC_G(gc_enabled)) { + gc_init(); + } + + return SUCCESS; +} +/* }}} */ + +static ZEND_INI_MH(OnUpdateScriptEncoding) /* {{{ */ +{ + if (!CG(multibyte)) { + return FAILURE; + } + if (!zend_multibyte_get_functions()) { + return SUCCESS; + } + return zend_multibyte_set_script_encoding_by_string(new_value ? new_value->val : NULL, new_value ? new_value->len : 0); +} +/* }}} */ + +static ZEND_INI_MH(OnUpdateAssertions) /* {{{ */ +{ + zend_long *p, val; +#ifndef ZTS + char *base = (char *) mh_arg2; +#else + char *base; + + base = (char *) ts_resource(*((int *) mh_arg2)); +#endif + + p = (zend_long *) (base+(size_t) mh_arg1); + + val = zend_atol(new_value->val, (int)new_value->len); + + if (stage != ZEND_INI_STAGE_STARTUP && + stage != ZEND_INI_STAGE_SHUTDOWN && + *p != val && + (*p < 0 || val < 0)) { + zend_error(E_WARNING, "zend.assertions may be completely enabled or disabled only in php.ini"); + return FAILURE; + } + + *p = val; + return SUCCESS; +} +/* }}} */ + +ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) + STD_ZEND_INI_BOOLEAN("zend.assertions", "1", ZEND_INI_ALL, OnUpdateAssertions, assertions, zend_executor_globals, executor_globals) + STD_ZEND_INI_BOOLEAN("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, gc_enabled, zend_gc_globals, gc_globals) + STD_ZEND_INI_BOOLEAN("zend.multibyte", "0", ZEND_INI_PERDIR, OnUpdateBool, multibyte, zend_compiler_globals, compiler_globals) + ZEND_INI_ENTRY("zend.script_encoding", NULL, ZEND_INI_ALL, OnUpdateScriptEncoding) + STD_ZEND_INI_BOOLEAN("zend.detect_unicode", "1", ZEND_INI_ALL, OnUpdateBool, detect_unicode, zend_compiler_globals, compiler_globals) +#ifdef ZEND_SIGNALS + STD_ZEND_INI_BOOLEAN("zend.signal_check", "0", ZEND_INI_SYSTEM, OnUpdateBool, check, zend_signal_globals_t, zend_signal_globals) +#endif +ZEND_INI_END() + + +#ifdef ZTS +ZEND_API int compiler_globals_id; +ZEND_API int executor_globals_id; +static HashTable *global_function_table = NULL; +static HashTable *global_class_table = NULL; +static HashTable *global_constants_table = NULL; +static HashTable *global_auto_globals_table = NULL; +static HashTable *global_persistent_list = NULL; +ZEND_TSRMLS_CACHE_DEFINE(); +#endif + +ZEND_API zend_utility_values zend_uv; + +/* version information */ +static char *zend_version_info; +static uint zend_version_info_length; +#define ZEND_CORE_VERSION_INFO "Zend Engine v" ZEND_VERSION ", Copyright (c) 1998-2015 Zend Technologies\n" +#define PRINT_ZVAL_INDENT 4 + +static void print_hash(zend_write_func_t write_func, HashTable *ht, int indent, zend_bool is_object) /* {{{ */ +{ + zval *tmp; + zend_string *string_key; + zend_ulong num_key; + int i; + + for (i = 0; i < indent; i++) { + ZEND_PUTS_EX(" "); + } + ZEND_PUTS_EX("(\n"); + indent += PRINT_ZVAL_INDENT; + ZEND_HASH_FOREACH_KEY_VAL(ht, num_key, string_key, tmp) { + if (Z_TYPE_P(tmp) == IS_INDIRECT) { + tmp = Z_INDIRECT_P(tmp); + if (Z_TYPE_P(tmp) == IS_UNDEF) { + continue; + } + } + for (i = 0; i < indent; i++) { + ZEND_PUTS_EX(" "); + } + ZEND_PUTS_EX("["); + if (string_key) { + if (is_object) { + const char *prop_name, *class_name; + size_t prop_len; + int mangled = zend_unmangle_property_name_ex(string_key, &class_name, &prop_name, &prop_len); + + ZEND_WRITE_EX(prop_name, prop_len); + if (class_name && mangled == SUCCESS) { + if (class_name[0]=='*') { + ZEND_PUTS_EX(":protected"); + } else { + ZEND_PUTS_EX(":"); + ZEND_PUTS_EX(class_name); + ZEND_PUTS_EX(":private"); + } + } + } else { + ZEND_WRITE_EX(string_key->val, string_key->len); + } + } else { + char key[25]; + snprintf(key, sizeof(key), ZEND_LONG_FMT, num_key); + ZEND_PUTS_EX(key); + } + ZEND_PUTS_EX("] => "); + zend_print_zval_r_ex(write_func, tmp, indent+PRINT_ZVAL_INDENT); + ZEND_PUTS_EX("\n"); + } ZEND_HASH_FOREACH_END(); + indent -= PRINT_ZVAL_INDENT; + for (i = 0; i < indent; i++) { + ZEND_PUTS_EX(" "); + } + ZEND_PUTS_EX(")\n"); +} +/* }}} */ + +static void print_flat_hash(HashTable *ht) /* {{{ */ +{ + zval *tmp; + zend_string *string_key; + zend_ulong num_key; + int i = 0; + + ZEND_HASH_FOREACH_KEY_VAL_IND(ht, num_key, string_key, tmp) { + if (i++ > 0) { + ZEND_PUTS(","); + } + ZEND_PUTS("["); + if (string_key) { + ZEND_WRITE(string_key->val, string_key->len); + } else { + zend_printf(ZEND_ULONG_FMT, num_key); + } + ZEND_PUTS("] => "); + zend_print_flat_zval_r(tmp); + } ZEND_HASH_FOREACH_END(); +} +/* }}} */ + +ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy) /* {{{ */ +{ + if (Z_TYPE_P(expr) == IS_STRING) { + return 0; + } else { + ZVAL_STR(expr_copy, _zval_get_string_func(expr)); + return 1; + } +} +/* }}} */ + +ZEND_API size_t zend_print_zval(zval *expr, int indent) /* {{{ */ +{ + return zend_print_zval_ex(zend_write, expr, indent); +} +/* }}} */ + +ZEND_API size_t zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent) /* {{{ */ +{ + zend_string *str = zval_get_string(expr); + size_t len = str->len; + + if (len != 0) { + write_func(str->val, len); + } + + zend_string_release(str); + return len; +} +/* }}} */ + +ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */ +{ + switch (Z_TYPE_P(expr)) { + case IS_ARRAY: + ZEND_PUTS("Array ("); + if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) && + ++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) { + ZEND_PUTS(" *RECURSION*"); + Z_ARRVAL_P(expr)->u.v.nApplyCount--; + return; + } + print_flat_hash(Z_ARRVAL_P(expr)); + ZEND_PUTS(")"); + if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) { + Z_ARRVAL_P(expr)->u.v.nApplyCount--; + } + break; + case IS_OBJECT: + { + HashTable *properties = NULL; + zend_string *class_name = Z_OBJ_HANDLER_P(expr, get_class_name)(Z_OBJ_P(expr)); + zend_printf("%s Object (", class_name->val); + zend_string_release(class_name); + + if (Z_OBJ_APPLY_COUNT_P(expr) > 0) { + ZEND_PUTS(" *RECURSION*"); + return; + } + + if (Z_OBJ_HANDLER_P(expr, get_properties)) { + properties = Z_OBJPROP_P(expr); + } + if (properties) { + Z_OBJ_INC_APPLY_COUNT_P(expr); + print_flat_hash(properties); + Z_OBJ_DEC_APPLY_COUNT_P(expr); + } + ZEND_PUTS(")"); + break; + } + default: + zend_print_variable(expr); + break; + } +} +/* }}} */ + +ZEND_API void zend_print_zval_r(zval *expr, int indent) /* {{{ */ +{ + zend_print_zval_r_ex(zend_write, expr, indent); +} +/* }}} */ + +ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int indent) /* {{{ */ +{ + ZVAL_DEREF(expr); + switch (Z_TYPE_P(expr)) { + case IS_ARRAY: + ZEND_PUTS_EX("Array\n"); + if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) && + ++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) { + ZEND_PUTS_EX(" *RECURSION*"); + Z_ARRVAL_P(expr)->u.v.nApplyCount--; + return; + } + print_hash(write_func, Z_ARRVAL_P(expr), indent, 0); + if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) { + Z_ARRVAL_P(expr)->u.v.nApplyCount--; + } + break; + case IS_OBJECT: + { + HashTable *properties; + int is_temp; + + zend_string *class_name = Z_OBJ_HANDLER_P(expr, get_class_name)(Z_OBJ_P(expr)); + ZEND_PUTS_EX(class_name->val); + zend_string_release(class_name); + + ZEND_PUTS_EX(" Object\n"); + if (Z_OBJ_APPLY_COUNT_P(expr) > 0) { + ZEND_PUTS_EX(" *RECURSION*"); + return; + } + if ((properties = Z_OBJDEBUG_P(expr, is_temp)) == NULL) { + break; + } + + Z_OBJ_INC_APPLY_COUNT_P(expr); + print_hash(write_func, properties, indent, 1); + Z_OBJ_DEC_APPLY_COUNT_P(expr); + + if (is_temp) { + zend_hash_destroy(properties); + FREE_HASHTABLE(properties); + } + break; + } + default: + zend_print_zval_ex(write_func, expr, indent); + break; + } +} +/* }}} */ + +static FILE *zend_fopen_wrapper(const char *filename, zend_string **opened_path) /* {{{ */ +{ + if (opened_path) { + *opened_path = zend_string_init(filename, strlen(filename), 0); + } + return fopen(filename, "rb"); +} +/* }}} */ + +#ifdef ZTS +static zend_bool short_tags_default = 1; +static uint32_t compiler_options_default = ZEND_COMPILE_DEFAULT; +#else +# define short_tags_default 1 +# define compiler_options_default ZEND_COMPILE_DEFAULT +#endif + +static void zend_set_default_compile_time_values(void) /* {{{ */ +{ + /* default compile-time values */ + CG(short_tags) = short_tags_default; + CG(compiler_options) = compiler_options_default; +} +/* }}} */ + +#ifdef ZEND_WIN32 +static void zend_get_windows_version_info(OSVERSIONINFOEX *osvi) /* {{{ */ +{ + ZeroMemory(osvi, sizeof(OSVERSIONINFOEX)); + osvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if(!GetVersionEx((OSVERSIONINFO *) osvi)) { + ZEND_ASSERT(0); /* Should not happen as sizeof is used. */ + } +} +/* }}} */ +#endif + +static void zend_init_exception_op(void) /* {{{ */ +{ + memset(EG(exception_op), 0, sizeof(EG(exception_op))); + EG(exception_op)[0].opcode = ZEND_HANDLE_EXCEPTION; + EG(exception_op)[0].op1_type = IS_UNUSED; + EG(exception_op)[0].op2_type = IS_UNUSED; + EG(exception_op)[0].result_type = IS_UNUSED; + ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)); + EG(exception_op)[1].opcode = ZEND_HANDLE_EXCEPTION; + EG(exception_op)[1].op1_type = IS_UNUSED; + EG(exception_op)[1].op2_type = IS_UNUSED; + EG(exception_op)[1].result_type = IS_UNUSED; + ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)+1); + EG(exception_op)[2].opcode = ZEND_HANDLE_EXCEPTION; + EG(exception_op)[2].op1_type = IS_UNUSED; + EG(exception_op)[2].op2_type = IS_UNUSED; + EG(exception_op)[2].result_type = IS_UNUSED; + ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)+2); +} +/* }}} */ + +static void zend_init_call_trampoline_op(void) /* {{{ */ +{ + memset(&EG(call_trampoline_op), 0, sizeof(EG(call_trampoline_op))); + EG(call_trampoline_op).opcode = ZEND_CALL_TRAMPOLINE; + EG(call_trampoline_op).op1_type = IS_UNUSED; + EG(call_trampoline_op).op2_type = IS_UNUSED; + EG(call_trampoline_op).result_type = IS_UNUSED; + ZEND_VM_SET_OPCODE_HANDLER(&EG(call_trampoline_op)); +} +/* }}} */ + +#ifdef ZTS +static void function_copy_ctor(zval *zv) +{ + zend_function *old_func = Z_FUNC_P(zv); + Z_FUNC_P(zv) = pemalloc(sizeof(zend_internal_function), 1); + memcpy(Z_FUNC_P(zv), old_func, sizeof(zend_internal_function)); + function_add_ref(Z_FUNC_P(zv)); +} + +static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{{ */ +{ + compiler_globals->compiled_filename = NULL; + + compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); + zend_hash_init_ex(compiler_globals->function_table, 1024, NULL, ZEND_FUNCTION_DTOR, 1, 0); + zend_hash_copy(compiler_globals->function_table, global_function_table, function_copy_ctor); + + compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); + zend_hash_init_ex(compiler_globals->class_table, 64, NULL, ZEND_CLASS_DTOR, 1, 0); + zend_hash_copy(compiler_globals->class_table, global_class_table, zend_class_add_ref); + + zend_set_default_compile_time_values(); + + compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable)); + zend_hash_init_ex(compiler_globals->auto_globals, 8, NULL, NULL, 1, 0); + zend_hash_copy(compiler_globals->auto_globals, global_auto_globals_table, NULL /* empty element */); + + compiler_globals->last_static_member = zend_hash_num_elements(compiler_globals->class_table); + if (compiler_globals->last_static_member) { + compiler_globals->static_members_table = calloc(compiler_globals->last_static_member, sizeof(zval*)); + } else { + compiler_globals->static_members_table = NULL; + } + compiler_globals->script_encoding_list = NULL; + +#ifdef ZTS + zend_interned_empty_string_init(&compiler_globals->empty_string); + + memset(compiler_globals->one_char_string, 0, sizeof(compiler_globals->one_char_string)); +#endif +} +/* }}} */ + +static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{{ */ +{ + if (compiler_globals->function_table != GLOBAL_FUNCTION_TABLE) { + zend_hash_destroy(compiler_globals->function_table); + free(compiler_globals->function_table); + } + if (compiler_globals->class_table != GLOBAL_CLASS_TABLE) { + zend_hash_destroy(compiler_globals->class_table); + free(compiler_globals->class_table); + } + if (compiler_globals->auto_globals != GLOBAL_AUTO_GLOBALS_TABLE) { + zend_hash_destroy(compiler_globals->auto_globals); + free(compiler_globals->auto_globals); + } + if (compiler_globals->static_members_table) { + free(compiler_globals->static_members_table); + } + if (compiler_globals->script_encoding_list) { + pefree((char*)compiler_globals->script_encoding_list, 1); + } + compiler_globals->last_static_member = 0; + +#ifdef ZTS + zend_interned_empty_string_free(&compiler_globals->empty_string); +#endif +} +/* }}} */ + +static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{{ */ +{ + ZEND_TSRMLS_CACHE_UPDATE(); + + zend_startup_constants(); + zend_copy_constants(EG(zend_constants), GLOBAL_CONSTANTS_TABLE); + zend_init_rsrc_plist(); + zend_init_exception_op(); + zend_init_call_trampoline_op(); + memset(&executor_globals->trampoline, 0, sizeof(zend_op_array)); + executor_globals->lambda_count = 0; + ZVAL_UNDEF(&executor_globals->user_error_handler); + ZVAL_UNDEF(&executor_globals->user_exception_handler); + executor_globals->in_autoload = NULL; + executor_globals->current_execute_data = NULL; + executor_globals->current_module = NULL; + executor_globals->exit_status = 0; +#if XPFPA_HAVE_CW + executor_globals->saved_fpu_cw = 0; +#endif + executor_globals->saved_fpu_cw_ptr = NULL; + executor_globals->active = 0; + executor_globals->bailout = NULL; + executor_globals->error_handling = EH_NORMAL; + executor_globals->exception_class = NULL; + executor_globals->exception = NULL; + executor_globals->objects_store.object_buckets = NULL; +#ifdef ZEND_WIN32 + zend_get_windows_version_info(&executor_globals->windows_version_info); +#endif +} +/* }}} */ + +static void executor_globals_dtor(zend_executor_globals *executor_globals) /* {{{ */ +{ +#ifdef ZTS + zend_ini_dtor(executor_globals->ini_directives); +#else + zend_ini_shutdown(); +#endif + if (&executor_globals->persistent_list != global_persistent_list) { + zend_destroy_rsrc_list(&executor_globals->persistent_list); + } + if (executor_globals->zend_constants != GLOBAL_CONSTANTS_TABLE) { + zend_hash_destroy(executor_globals->zend_constants); + free(executor_globals->zend_constants); + } +} +/* }}} */ + +static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ +{ + if (zend_copy_ini_directives() == SUCCESS) { + zend_ini_refresh_caches(ZEND_INI_STAGE_STARTUP); + } +} +/* }}} */ +#endif + +#if defined(__FreeBSD__) || defined(__DragonFly__) +/* FreeBSD and DragonFly floating point precision fix */ +#include +#endif + +static void ini_scanner_globals_ctor(zend_ini_scanner_globals *scanner_globals_p) /* {{{ */ +{ + memset(scanner_globals_p, 0, sizeof(*scanner_globals_p)); +} +/* }}} */ + +static void php_scanner_globals_ctor(zend_php_scanner_globals *scanner_globals_p) /* {{{ */ +{ + memset(scanner_globals_p, 0, sizeof(*scanner_globals_p)); +} +/* }}} */ + +void zend_init_opcodes_handlers(void); + +static void module_destructor_zval(zval *zv) /* {{{ */ +{ + zend_module_entry *module = (zend_module_entry*)Z_PTR_P(zv); + + module_destructor(module); + free(module); +} +/* }}} */ + +static void auto_global_dtor(zval *zv) /* {{{ */ +{ + free(Z_PTR_P(zv)); +} +/* }}} */ + +static zend_bool php_auto_globals_create_globals(zend_string *name) /* {{{ */ +{ + zval globals; + + ZVAL_ARR(&globals, &EG(symbol_table)); + Z_TYPE_INFO_P(&globals) = IS_ARRAY | (IS_TYPE_SYMBOLTABLE << Z_TYPE_FLAGS_SHIFT); + ZVAL_NEW_REF(&globals, &globals); + zend_hash_update(&EG(symbol_table), name, &globals); + return 0; +} +/* }}} */ + +int zend_startup(zend_utility_functions *utility_functions, char **extensions) /* {{{ */ +{ +#ifdef ZTS + zend_compiler_globals *compiler_globals; + zend_executor_globals *executor_globals; + extern ZEND_API ts_rsrc_id ini_scanner_globals_id; + extern ZEND_API ts_rsrc_id language_scanner_globals_id; + ZEND_TSRMLS_CACHE_UPDATE(); +#else + extern zend_ini_scanner_globals ini_scanner_globals; + extern zend_php_scanner_globals language_scanner_globals; +#endif + + start_memory_manager(); + + virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */ + +#if defined(__FreeBSD__) || defined(__DragonFly__) + /* FreeBSD and DragonFly floating point precision fix */ + fpsetmask(0); +#endif + + zend_startup_strtod(); + zend_startup_extensions_mechanism(); + + /* Set up utility functions and values */ + zend_error_cb = utility_functions->error_function; + zend_printf = utility_functions->printf_function; + zend_write = (zend_write_func_t) utility_functions->write_function; + zend_fopen = utility_functions->fopen_function; + if (!zend_fopen) { + zend_fopen = zend_fopen_wrapper; + } + zend_stream_open_function = utility_functions->stream_open_function; + zend_message_dispatcher_p = utility_functions->message_handler; +#ifndef ZEND_SIGNALS + zend_block_interruptions = utility_functions->block_interruptions; + zend_unblock_interruptions = utility_functions->unblock_interruptions; +#endif + zend_get_configuration_directive_p = utility_functions->get_configuration_directive; + zend_ticks_function = utility_functions->ticks_function; + zend_on_timeout = utility_functions->on_timeout; + zend_vspprintf = utility_functions->vspprintf_function; + zend_vstrpprintf = utility_functions->vstrpprintf_function; + zend_getenv = utility_functions->getenv_function; + zend_resolve_path = utility_functions->resolve_path_function; + +#if HAVE_DTRACE +/* build with dtrace support */ + zend_compile_file = dtrace_compile_file; + zend_execute_ex = dtrace_execute_ex; + zend_execute_internal = dtrace_execute_internal; +#else + zend_compile_file = compile_file; + zend_execute_ex = execute_ex; + zend_execute_internal = NULL; +#endif /* HAVE_SYS_SDT_H */ + zend_compile_string = compile_string; + zend_throw_exception_hook = NULL; + + /* Set up the default garbage collection implementation. */ + gc_collect_cycles = zend_gc_collect_cycles; + + zend_init_opcodes_handlers(); + + /* set up version */ + zend_version_info = strdup(ZEND_CORE_VERSION_INFO); + zend_version_info_length = sizeof(ZEND_CORE_VERSION_INFO) - 1; + + GLOBAL_FUNCTION_TABLE = (HashTable *) malloc(sizeof(HashTable)); + GLOBAL_CLASS_TABLE = (HashTable *) malloc(sizeof(HashTable)); + GLOBAL_AUTO_GLOBALS_TABLE = (HashTable *) malloc(sizeof(HashTable)); + GLOBAL_CONSTANTS_TABLE = (HashTable *) malloc(sizeof(HashTable)); + + zend_hash_init_ex(GLOBAL_FUNCTION_TABLE, 1024, NULL, ZEND_FUNCTION_DTOR, 1, 0); + zend_hash_init_ex(GLOBAL_CLASS_TABLE, 64, NULL, ZEND_CLASS_DTOR, 1, 0); + zend_hash_init_ex(GLOBAL_AUTO_GLOBALS_TABLE, 8, NULL, auto_global_dtor, 1, 0); + zend_hash_init_ex(GLOBAL_CONSTANTS_TABLE, 128, NULL, ZEND_CONSTANT_DTOR, 1, 0); + + zend_hash_init_ex(&module_registry, 32, NULL, module_destructor_zval, 1, 0); + zend_init_rsrc_list_dtors(); + +#ifdef ZTS + ts_allocate_id(&compiler_globals_id, sizeof(zend_compiler_globals), (ts_allocate_ctor) compiler_globals_ctor, (ts_allocate_dtor) compiler_globals_dtor); + ts_allocate_id(&executor_globals_id, sizeof(zend_executor_globals), (ts_allocate_ctor) executor_globals_ctor, (ts_allocate_dtor) executor_globals_dtor); + ts_allocate_id(&language_scanner_globals_id, sizeof(zend_php_scanner_globals), (ts_allocate_ctor) php_scanner_globals_ctor, NULL); + ts_allocate_id(&ini_scanner_globals_id, sizeof(zend_ini_scanner_globals), (ts_allocate_ctor) ini_scanner_globals_ctor, NULL); + compiler_globals = ts_resource(compiler_globals_id); + executor_globals = ts_resource(executor_globals_id); + + compiler_globals_dtor(compiler_globals); + compiler_globals->in_compilation = 0; + compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); + + *compiler_globals->function_table = *GLOBAL_FUNCTION_TABLE; + *compiler_globals->class_table = *GLOBAL_CLASS_TABLE; + compiler_globals->auto_globals = GLOBAL_AUTO_GLOBALS_TABLE; + + zend_hash_destroy(executor_globals->zend_constants); + *executor_globals->zend_constants = *GLOBAL_CONSTANTS_TABLE; +#else + ini_scanner_globals_ctor(&ini_scanner_globals); + php_scanner_globals_ctor(&language_scanner_globals); + zend_set_default_compile_time_values(); +#endif + EG(error_reporting) = E_ALL & ~E_NOTICE; + + zend_interned_strings_init(); + zend_startup_builtin_functions(); + zend_register_standard_constants(); + zend_register_auto_global(zend_string_init("GLOBALS", sizeof("GLOBALS") - 1, 1), 1, php_auto_globals_create_globals); + +#ifndef ZTS + zend_init_rsrc_plist(); + zend_init_exception_op(); + zend_init_call_trampoline_op(); +#endif + + zend_ini_startup(); + +#ifdef ZTS + tsrm_set_new_thread_end_handler(zend_new_thread_end_handler); +#endif + +#ifdef ZEND_SIGNALS + zend_signal_startup(); +#endif + + return SUCCESS; +} +/* }}} */ + +void zend_register_standard_ini_entries(void) /* {{{ */ +{ + int module_number = 0; + + REGISTER_INI_ENTRIES(); +} +/* }}} */ + +/* Unlink the global (r/o) copies of the class, function and constant tables, + * and use a fresh r/w copy for the startup thread + */ +void zend_post_startup(void) /* {{{ */ +{ +#ifdef ZTS + zend_encoding **script_encoding_list; + + zend_compiler_globals *compiler_globals = ts_resource(compiler_globals_id); + zend_executor_globals *executor_globals = ts_resource(executor_globals_id); + + *GLOBAL_FUNCTION_TABLE = *compiler_globals->function_table; + *GLOBAL_CLASS_TABLE = *compiler_globals->class_table; + *GLOBAL_CONSTANTS_TABLE = *executor_globals->zend_constants; + + short_tags_default = CG(short_tags); + compiler_options_default = CG(compiler_options); + + zend_destroy_rsrc_list(&EG(persistent_list)); + free(compiler_globals->function_table); + free(compiler_globals->class_table); + if ((script_encoding_list = (zend_encoding **)compiler_globals->script_encoding_list)) { + compiler_globals_ctor(compiler_globals); + compiler_globals->script_encoding_list = (const zend_encoding **)script_encoding_list; + } else { + compiler_globals_ctor(compiler_globals); + } + free(EG(zend_constants)); + + virtual_cwd_deactivate(); + + executor_globals_ctor(executor_globals); + global_persistent_list = &EG(persistent_list); + zend_copy_ini_directives(); +#else +#ifdef ZEND_WIN32 + zend_get_windows_version_info(&EG(windows_version_info)); +#endif + virtual_cwd_deactivate(); +#endif +} +/* }}} */ + +void zend_shutdown(void) /* {{{ */ +{ + zend_destroy_rsrc_list(&EG(persistent_list)); + if (EG(active)) + { + /* + * The order of destruction is important here. + * See bugs #65463 and 66036. + */ + zend_function *func; + zend_class_entry *ce; + + ZEND_HASH_REVERSE_FOREACH_PTR(GLOBAL_FUNCTION_TABLE, func) { + if (func->type == ZEND_USER_FUNCTION) { + zend_cleanup_op_array_data((zend_op_array *) func); + } + } ZEND_HASH_FOREACH_END(); + ZEND_HASH_REVERSE_FOREACH_PTR(GLOBAL_CLASS_TABLE, ce) { + if (ce->type == ZEND_USER_CLASS) { + zend_cleanup_user_class_data(ce); + } else { + break; + } + } ZEND_HASH_FOREACH_END(); + zend_cleanup_internal_classes(); + zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) clean_non_persistent_function_full); + zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) clean_non_persistent_class_full); + } + zend_destroy_modules(); + + virtual_cwd_deactivate(); + virtual_cwd_shutdown(); + + zend_hash_destroy(GLOBAL_FUNCTION_TABLE); + zend_hash_destroy(GLOBAL_CLASS_TABLE); + + zend_hash_destroy(GLOBAL_AUTO_GLOBALS_TABLE); + free(GLOBAL_AUTO_GLOBALS_TABLE); + + zend_shutdown_extensions(); + free(zend_version_info); + + free(GLOBAL_FUNCTION_TABLE); + free(GLOBAL_CLASS_TABLE); + + zend_hash_destroy(GLOBAL_CONSTANTS_TABLE); + free(GLOBAL_CONSTANTS_TABLE); + zend_shutdown_strtod(); + +#ifdef ZTS + GLOBAL_FUNCTION_TABLE = NULL; + GLOBAL_CLASS_TABLE = NULL; + GLOBAL_AUTO_GLOBALS_TABLE = NULL; + GLOBAL_CONSTANTS_TABLE = NULL; +#endif + zend_destroy_rsrc_list_dtors(); + + zend_interned_strings_dtor(); +} +/* }}} */ + +void zend_set_utility_values(zend_utility_values *utility_values) /* {{{ */ +{ + zend_uv = *utility_values; + zend_uv.import_use_extension_length = (uint)strlen(zend_uv.import_use_extension); +} +/* }}} */ + +/* this should be compatible with the standard zenderror */ +void zenderror(const char *error) /* {{{ */ +{ + if (EG(exception)) { + /* An exception was thrown in the lexer, don't throw another in the parser. */ + return; + } + + zend_throw_exception(zend_get_parse_exception(), error, E_PARSE); +} +/* }}} */ + +BEGIN_EXTERN_C() +ZEND_API void _zend_bailout(char *filename, uint lineno) /* {{{ */ +{ + + if (!EG(bailout)) { + zend_output_debug_string(1, "%s(%d) : Bailed out without a bailout address!", filename, lineno); + exit(-1); + } + CG(unclean_shutdown) = 1; + CG(active_class_entry) = NULL; + CG(in_compilation) = 0; + EG(current_execute_data) = NULL; + LONGJMP(*EG(bailout), FAILURE); +} +/* }}} */ +END_EXTERN_C() + +ZEND_API void zend_append_version_info(const zend_extension *extension) /* {{{ */ +{ + char *new_info; + uint new_info_length; + + new_info_length = (uint)(sizeof(" with v, , by \n") + + strlen(extension->name) + + strlen(extension->version) + + strlen(extension->copyright) + + strlen(extension->author)); + + new_info = (char *) malloc(new_info_length + 1); + + snprintf(new_info, new_info_length, " with %s v%s, %s, by %s\n", extension->name, extension->version, extension->copyright, extension->author); + + zend_version_info = (char *) realloc(zend_version_info, zend_version_info_length+new_info_length + 1); + strncat(zend_version_info, new_info, new_info_length); + zend_version_info_length += new_info_length; + free(new_info); +} +/* }}} */ + +ZEND_API char *get_zend_version(void) /* {{{ */ +{ + return zend_version_info; +} +/* }}} */ + +ZEND_API void zend_activate(void) /* {{{ */ +{ +#ifdef ZTS + virtual_cwd_activate(); +#endif + gc_reset(); + init_compiler(); + init_executor(); + startup_scanner(); +} +/* }}} */ + +void zend_call_destructors(void) /* {{{ */ +{ + zend_try { + shutdown_destructors(); + } zend_end_try(); +} +/* }}} */ + +ZEND_API void zend_deactivate(void) /* {{{ */ +{ + /* we're no longer executing anything */ + EG(current_execute_data) = NULL; + + zend_try { + shutdown_scanner(); + } zend_end_try(); + + /* shutdown_executor() takes care of its own bailout handling */ + shutdown_executor(); + + zend_try { + shutdown_compiler(); + } zend_end_try(); + + zend_destroy_rsrc_list(&EG(regular_list)); + +#if GC_BENCH + fprintf(stderr, "GC Statistics\n"); + fprintf(stderr, "-------------\n"); + fprintf(stderr, "Runs: %d\n", GC_G(gc_runs)); + fprintf(stderr, "Collected: %d\n", GC_G(collected)); + fprintf(stderr, "Root buffer length: %d\n", GC_G(root_buf_length)); + fprintf(stderr, "Root buffer peak: %d\n\n", GC_G(root_buf_peak)); + fprintf(stderr, " Possible Remove from Marked\n"); + fprintf(stderr, " Root Buffered buffer grey\n"); + fprintf(stderr, " -------- -------- ----------- ------\n"); + fprintf(stderr, "ZVAL %8d %8d %9d %8d\n", GC_G(zval_possible_root), GC_G(zval_buffered), GC_G(zval_remove_from_buffer), GC_G(zval_marked_grey)); + fprintf(stderr, "ZOBJ %8d %8d %9d %8d\n", GC_G(zobj_possible_root), GC_G(zobj_buffered), GC_G(zobj_remove_from_buffer), GC_G(zobj_marked_grey)); +#endif + + zend_try { + zend_ini_deactivate(); + } zend_end_try(); +} +/* }}} */ + +BEGIN_EXTERN_C() +ZEND_API void zend_message_dispatcher(zend_long message, const void *data) /* {{{ */ +{ + if (zend_message_dispatcher_p) { + zend_message_dispatcher_p(message, data); + } +} +/* }}} */ +END_EXTERN_C() + +ZEND_API zval *zend_get_configuration_directive(zend_string *name) /* {{{ */ +{ + if (zend_get_configuration_directive_p) { + return zend_get_configuration_directive_p(name); + } else { + return NULL; + } +} +/* }}} */ + +#define SAVE_STACK(stack) do { \ + if (CG(stack).top) { \ + memcpy(&stack, &CG(stack), sizeof(zend_stack)); \ + CG(stack).top = CG(stack).max = 0; \ + CG(stack).elements = NULL; \ + } else { \ + stack.top = 0; \ + } \ + } while (0) + +#define RESTORE_STACK(stack) do { \ + if (stack.top) { \ + zend_stack_destroy(&CG(stack)); \ + memcpy(&CG(stack), &stack, sizeof(zend_stack)); \ + } \ + } while (0) + +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) +ZEND_API void zend_error(int type, const char *format, ...) /* {{{ */ +#else +static void zend_error_va_list(int type, const char *format, va_list args) +#endif +{ + char *str; + int len; +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_list args; +#endif + va_list usr_copy; + zval params[5]; + zval retval; + const char *error_filename; + uint error_lineno = 0; + zval orig_user_error_handler; + zend_bool in_compilation; + zend_class_entry *saved_class_entry; + zend_stack loop_var_stack; + zend_stack delayed_oplines_stack; + zend_array *symbol_table; + + if (type & E_EXCEPTION) { + type &= ~E_EXCEPTION; + //TODO: we can't convert compile-time errors to exceptions yet??? + if (EG(current_execute_data) && !CG(in_compilation)) { + char *message = NULL; + +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_start(args, format); +#endif + zend_vspprintf(&message, 0, format, args); + zend_throw_exception(zend_get_engine_exception(), message, type); + efree(message); +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_end(args); +#endif + return; + } + } + + /* Report about uncaught exception in case of fatal errors */ + if (EG(exception)) { + zend_execute_data *ex; + const zend_op *opline; + + switch (type) { + case E_CORE_ERROR: + case E_ERROR: + case E_RECOVERABLE_ERROR: + case E_PARSE: + case E_COMPILE_ERROR: + case E_USER_ERROR: + ex = EG(current_execute_data); + opline = NULL; + while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) { + ex = ex->prev_execute_data; + } + if (ex && ex->opline->opcode == ZEND_HANDLE_EXCEPTION && + EG(opline_before_exception)) { + opline = EG(opline_before_exception); + } + zend_exception_error(EG(exception), E_WARNING); + EG(exception) = NULL; + if (opline) { + ex->opline = opline; + } + break; + default: + break; + } + } + + /* Obtain relevant filename and lineno */ + switch (type) { + case E_CORE_ERROR: + case E_CORE_WARNING: + error_filename = NULL; + error_lineno = 0; + break; + case E_PARSE: + case E_COMPILE_ERROR: + case E_COMPILE_WARNING: + case E_ERROR: + case E_NOTICE: + case E_STRICT: + case E_DEPRECATED: + case E_WARNING: + case E_USER_ERROR: + case E_USER_WARNING: + case E_USER_NOTICE: + case E_USER_DEPRECATED: + case E_RECOVERABLE_ERROR: + if (zend_is_compiling()) { + error_filename = zend_get_compiled_filename()->val; + error_lineno = zend_get_compiled_lineno(); + } else if (zend_is_executing()) { + error_filename = zend_get_executed_filename(); + if (error_filename[0] == '[') { /* [no active file] */ + error_filename = NULL; + error_lineno = 0; + } else { + error_lineno = zend_get_executed_lineno(); + } + } else { + error_filename = NULL; + error_lineno = 0; + } + break; + default: + error_filename = NULL; + error_lineno = 0; + break; + } + if (!error_filename) { + error_filename = "Unknown"; + } + +#ifdef HAVE_DTRACE + if (DTRACE_ERROR_ENABLED()) { + char *dtrace_error_buffer; +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_start(args, format); +#endif + zend_vspprintf(&dtrace_error_buffer, 0, format, args); + DTRACE_ERROR(dtrace_error_buffer, (char *)error_filename, error_lineno); + efree(dtrace_error_buffer); +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_end(args); +#endif + } +#endif /* HAVE_DTRACE */ + +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_start(args, format); +#endif + + /* if we don't have a user defined error handler */ + if (Z_TYPE(EG(user_error_handler)) == IS_UNDEF + || !(EG(user_error_handler_error_reporting) & type) + || EG(error_handling) != EH_NORMAL) { + zend_error_cb(type, error_filename, error_lineno, format, args); + } else switch (type) { + case E_ERROR: + case E_PARSE: + case E_CORE_ERROR: + case E_CORE_WARNING: + case E_COMPILE_ERROR: + case E_COMPILE_WARNING: + /* The error may not be safe to handle in user-space */ + zend_error_cb(type, error_filename, error_lineno, format, args); + break; + default: + /* Handle the error in user space */ +/* va_copy() is __va_copy() in old gcc versions. + * According to the autoconf manual, using + * memcpy(&dst, &src, sizeof(va_list)) + * gives maximum portability. */ +#ifndef va_copy +# ifdef __va_copy +# define va_copy(dest, src) __va_copy((dest), (src)) +# else +# define va_copy(dest, src) memcpy(&(dest), &(src), sizeof(va_list)) +# endif +#endif + va_copy(usr_copy, args); + len = (int)zend_vspprintf(&str, 0, format, usr_copy); + ZVAL_NEW_STR(¶ms[1], zend_string_init(str, len, 0)); + efree(str); +#ifdef va_copy + va_end(usr_copy); +#endif + + ZVAL_LONG(¶ms[0], type); + + if (error_filename) { + ZVAL_STRING(¶ms[2], error_filename); + } else { + ZVAL_NULL(¶ms[2]); + } + + ZVAL_LONG(¶ms[3], error_lineno); + + symbol_table = zend_rebuild_symbol_table(); + + /* during shutdown the symbol table table can be still null */ + if (!symbol_table) { + ZVAL_NULL(¶ms[4]); + } else { + ZVAL_ARR(¶ms[4], zend_array_dup(symbol_table)); + } + + ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler)); + ZVAL_UNDEF(&EG(user_error_handler)); + + /* User error handler may include() additinal PHP files. + * If an error was generated during comilation PHP will compile + * such scripts recursivly, but some CG() variables may be + * inconsistent. */ + + in_compilation = CG(in_compilation); + if (in_compilation) { + saved_class_entry = CG(active_class_entry); + CG(active_class_entry) = NULL; + SAVE_STACK(loop_var_stack); + SAVE_STACK(delayed_oplines_stack); + CG(in_compilation) = 0; + } + + if (call_user_function_ex(CG(function_table), NULL, &orig_user_error_handler, &retval, 5, params, 1, NULL) == SUCCESS) { + if (Z_TYPE(retval) != IS_UNDEF) { + if (Z_TYPE(retval) == IS_FALSE) { + zend_error_cb(type, error_filename, error_lineno, format, args); + } + zval_ptr_dtor(&retval); + } + } else if (!EG(exception)) { + /* The user error handler failed, use built-in error handler */ + zend_error_cb(type, error_filename, error_lineno, format, args); + } + + if (in_compilation) { + CG(active_class_entry) = saved_class_entry; + RESTORE_STACK(loop_var_stack); + RESTORE_STACK(delayed_oplines_stack); + CG(in_compilation) = 1; + } + + zval_ptr_dtor(¶ms[4]); + zval_ptr_dtor(¶ms[3]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[0]); + + if (Z_TYPE(EG(user_error_handler)) == IS_UNDEF) { + ZVAL_COPY_VALUE(&EG(user_error_handler), &orig_user_error_handler); + } else { + zval_ptr_dtor(&orig_user_error_handler); + } + break; + } + +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_end(args); +#endif + + if (type == E_PARSE) { + /* eval() errors do not affect exit_status */ + if (!(EG(current_execute_data) && + EG(current_execute_data)->func && + ZEND_USER_CODE(EG(current_execute_data)->func->type) && + EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL && + EG(current_execute_data)->opline->extended_value == ZEND_EVAL)) { + EG(exit_status) = 255; + } + } +} +/* }}} */ + +#ifdef HAVE_NORETURN +# ifdef HAVE_NORETURN_ALIAS +void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((alias("zend_error"),noreturn)); +# else +ZEND_API void zend_error(int type, const char *format, ...) /* {{{ */ +{ + va_list va; + + va_start(va, format); + zend_error_va_list(type, format, va); + va_end(va); +} + +ZEND_API ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) +{ + va_list va; + + va_start(va, format); + zend_error_va_list(type, format, va); + va_end(va); +} +/* }}} */ +# endif +#endif + +ZEND_API void zend_type_error(const char *format, ...) /* {{{ */ +{ + va_list va; + char *message = NULL; + + va_start(va, format); + zend_vspprintf(&message, 0, format, va); + zend_throw_exception(zend_get_type_exception(), message, E_ERROR); + efree(message); + va_end(va); +} /* }}} */ + +ZEND_API void zend_internal_type_error(zend_bool throw_exception, const char *format, ...) /* {{{ */ +{ + va_list va; + char *message = NULL; + + va_start(va, format); + zend_vspprintf(&message, 0, format, va); + if (throw_exception) { + zend_throw_exception(zend_get_type_exception(), message, E_ERROR); + } else { + zend_error(E_WARNING, message); + } + efree(message); + + va_end(va); +} /* }}} */ + +ZEND_API void zend_output_debug_string(zend_bool trigger_break, const char *format, ...) /* {{{ */ +{ +#if ZEND_DEBUG + va_list args; + + va_start(args, format); +# ifdef ZEND_WIN32 + { + char output_buf[1024]; + + vsnprintf(output_buf, 1024, format, args); + OutputDebugString(output_buf); + OutputDebugString("\n"); + if (trigger_break && IsDebuggerPresent()) { + DebugBreak(); + } + } +# else + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); +# endif + va_end(args); +#endif +} +/* }}} */ + +ZEND_API int zend_execute_scripts(int type, zval *retval, int file_count, ...) /* {{{ */ +{ + va_list files; + int i; + zend_file_handle *file_handle; + zend_op_array *op_array; + + va_start(files, file_count); + for (i = 0; i < file_count; i++) { + file_handle = va_arg(files, zend_file_handle *); + if (!file_handle) { + continue; + } + + op_array = zend_compile_file(file_handle, type); + if (file_handle->opened_path) { + zend_hash_add_empty_element(&EG(included_files), file_handle->opened_path); + } + zend_destroy_file_handle(file_handle); + if (op_array) { + zend_execute(op_array, retval); + zend_exception_restore(); + if (EG(exception)) { + if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { + zval orig_user_exception_handler; + zval params[1], retval2; + zend_object *old_exception; + old_exception = EG(exception); + EG(exception) = NULL; + ZVAL_OBJ(¶ms[0], old_exception); + ZVAL_COPY_VALUE(&orig_user_exception_handler, &EG(user_exception_handler)); + + if (call_user_function_ex(CG(function_table), NULL, &orig_user_exception_handler, &retval2, 1, params, 1, NULL) == SUCCESS) { + zval_ptr_dtor(&retval2); + if (EG(exception)) { + OBJ_RELEASE(EG(exception)); + EG(exception) = NULL; + } + OBJ_RELEASE(old_exception); + } else { + EG(exception) = old_exception; + zend_exception_error(EG(exception), E_ERROR); + } + } else { + zend_exception_error(EG(exception), E_ERROR); + } + } + destroy_op_array(op_array); + efree_size(op_array, sizeof(zend_op_array)); + } else if (type==ZEND_REQUIRE) { + va_end(files); + return FAILURE; + } + } + va_end(files); + + return SUCCESS; +} +/* }}} */ + +#define COMPILED_STRING_DESCRIPTION_FORMAT "%s(%d) : %s" + +ZEND_API char *zend_make_compiled_string_description(const char *name) /* {{{ */ +{ + const char *cur_filename; + int cur_lineno; + char *compiled_string_description; + + if (zend_is_compiling()) { + cur_filename = zend_get_compiled_filename()->val; + cur_lineno = zend_get_compiled_lineno(); + } else if (zend_is_executing()) { + cur_filename = zend_get_executed_filename(); + cur_lineno = zend_get_executed_lineno(); + } else { + cur_filename = "Unknown"; + cur_lineno = 0; + } + + zend_spprintf(&compiled_string_description, 0, COMPILED_STRING_DESCRIPTION_FORMAT, cur_filename, cur_lineno, name); + return compiled_string_description; +} +/* }}} */ + +void free_estring(char **str_p) /* {{{ */ +{ + efree(*str_p); +} +/* }}} */ + +void free_string_zval(zval *zv) /* {{{ */ +{ + zend_string *str = Z_PTR_P(zv); + zend_string_release(str); +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ diff --git a/src/main/resource/testFiles/php-src/revFiles/e76cf8_39753f_Zend#zend.c b/src/main/resource/testFiles/php-src/revFiles/e76cf8_39753f_Zend#zend.c new file mode 100644 index 0000000..3bd0d6e --- /dev/null +++ b/src/main/resource/testFiles/php-src/revFiles/e76cf8_39753f_Zend#zend.c @@ -0,0 +1,1472 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Andi Gutmans | + | Zeev Suraski | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "zend.h" +#include "zend_extensions.h" +#include "zend_modules.h" +#include "zend_constants.h" +#include "zend_list.h" +#include "zend_API.h" +#include "zend_exceptions.h" +#include "zend_builtin_functions.h" +#include "zend_ini.h" +#include "zend_vm.h" +#include "zend_dtrace.h" +#include "zend_virtual_cwd.h" + +#ifdef ZTS +# define GLOBAL_FUNCTION_TABLE global_function_table +# define GLOBAL_CLASS_TABLE global_class_table +# define GLOBAL_CONSTANTS_TABLE global_constants_table +# define GLOBAL_AUTO_GLOBALS_TABLE global_auto_globals_table +#else +# define GLOBAL_FUNCTION_TABLE CG(function_table) +# define GLOBAL_CLASS_TABLE CG(class_table) +# define GLOBAL_AUTO_GLOBALS_TABLE CG(auto_globals) +# define GLOBAL_CONSTANTS_TABLE EG(zend_constants) +#endif + +/* true multithread-shared globals */ +ZEND_API zend_class_entry *zend_standard_class_def = NULL; +ZEND_API size_t (*zend_printf)(const char *format, ...); +ZEND_API zend_write_func_t zend_write; +ZEND_API FILE *(*zend_fopen)(const char *filename, zend_string **opened_path); +ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle); +ZEND_API void (*zend_block_interruptions)(void); +ZEND_API void (*zend_unblock_interruptions)(void); +ZEND_API void (*zend_ticks_function)(int ticks); +ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); +size_t (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); +zend_string *(*zend_vstrpprintf)(size_t max_len, const char *format, va_list ap); +ZEND_API char *(*zend_getenv)(char *name, size_t name_len); +ZEND_API zend_string *(*zend_resolve_path)(const char *filename, int filename_len); + +void (*zend_on_timeout)(int seconds); + +static void (*zend_message_dispatcher_p)(zend_long message, const void *data); +static zval *(*zend_get_configuration_directive_p)(zend_string *name); + +static ZEND_INI_MH(OnUpdateErrorReporting) /* {{{ */ +{ + if (!new_value) { + EG(error_reporting) = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED; + } else { + EG(error_reporting) = atoi(new_value->val); + } + return SUCCESS; +} +/* }}} */ + +static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */ +{ + OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); + + if (GC_G(gc_enabled)) { + gc_init(); + } + + return SUCCESS; +} +/* }}} */ + +static ZEND_INI_MH(OnUpdateScriptEncoding) /* {{{ */ +{ + if (!CG(multibyte)) { + return FAILURE; + } + if (!zend_multibyte_get_functions()) { + return SUCCESS; + } + return zend_multibyte_set_script_encoding_by_string(new_value ? new_value->val : NULL, new_value ? new_value->len : 0); +} +/* }}} */ + +static ZEND_INI_MH(OnUpdateAssertions) /* {{{ */ +{ + zend_long *p, val; +#ifndef ZTS + char *base = (char *) mh_arg2; +#else + char *base; + + base = (char *) ts_resource(*((int *) mh_arg2)); +#endif + + p = (zend_long *) (base+(size_t) mh_arg1); + + val = zend_atol(new_value->val, (int)new_value->len); + + if (stage != ZEND_INI_STAGE_STARTUP && + stage != ZEND_INI_STAGE_SHUTDOWN && + *p != val && + (*p < 0 || val < 0)) { + zend_error(E_WARNING, "zend.assertions may be completely enabled or disabled only in php.ini"); + return FAILURE; + } + + *p = val; + return SUCCESS; +} +/* }}} */ + +ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) + STD_ZEND_INI_BOOLEAN("zend.assertions", "1", ZEND_INI_ALL, OnUpdateAssertions, assertions, zend_executor_globals, executor_globals) + STD_ZEND_INI_BOOLEAN("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, gc_enabled, zend_gc_globals, gc_globals) + STD_ZEND_INI_BOOLEAN("zend.multibyte", "0", ZEND_INI_PERDIR, OnUpdateBool, multibyte, zend_compiler_globals, compiler_globals) + ZEND_INI_ENTRY("zend.script_encoding", NULL, ZEND_INI_ALL, OnUpdateScriptEncoding) + STD_ZEND_INI_BOOLEAN("zend.detect_unicode", "1", ZEND_INI_ALL, OnUpdateBool, detect_unicode, zend_compiler_globals, compiler_globals) +#ifdef ZEND_SIGNALS + STD_ZEND_INI_BOOLEAN("zend.signal_check", "0", ZEND_INI_SYSTEM, OnUpdateBool, check, zend_signal_globals_t, zend_signal_globals) +#endif +ZEND_INI_END() + + +#ifdef ZTS +ZEND_API int compiler_globals_id; +ZEND_API int executor_globals_id; +static HashTable *global_function_table = NULL; +static HashTable *global_class_table = NULL; +static HashTable *global_constants_table = NULL; +static HashTable *global_auto_globals_table = NULL; +static HashTable *global_persistent_list = NULL; +ZEND_TSRMLS_CACHE_DEFINE(); +#endif + +ZEND_API zend_utility_values zend_uv; + +/* version information */ +static char *zend_version_info; +static uint zend_version_info_length; +#define ZEND_CORE_VERSION_INFO "Zend Engine v" ZEND_VERSION ", Copyright (c) 1998-2015 Zend Technologies\n" +#define PRINT_ZVAL_INDENT 4 + +static void print_hash(zend_write_func_t write_func, HashTable *ht, int indent, zend_bool is_object) /* {{{ */ +{ + zval *tmp; + zend_string *string_key; + zend_ulong num_key; + int i; + + for (i = 0; i < indent; i++) { + ZEND_PUTS_EX(" "); + } + ZEND_PUTS_EX("(\n"); + indent += PRINT_ZVAL_INDENT; + ZEND_HASH_FOREACH_KEY_VAL(ht, num_key, string_key, tmp) { + if (Z_TYPE_P(tmp) == IS_INDIRECT) { + tmp = Z_INDIRECT_P(tmp); + if (Z_TYPE_P(tmp) == IS_UNDEF) { + continue; + } + } + for (i = 0; i < indent; i++) { + ZEND_PUTS_EX(" "); + } + ZEND_PUTS_EX("["); + if (string_key) { + if (is_object) { + const char *prop_name, *class_name; + size_t prop_len; + int mangled = zend_unmangle_property_name_ex(string_key, &class_name, &prop_name, &prop_len); + + ZEND_WRITE_EX(prop_name, prop_len); + if (class_name && mangled == SUCCESS) { + if (class_name[0]=='*') { + ZEND_PUTS_EX(":protected"); + } else { + ZEND_PUTS_EX(":"); + ZEND_PUTS_EX(class_name); + ZEND_PUTS_EX(":private"); + } + } + } else { + ZEND_WRITE_EX(string_key->val, string_key->len); + } + } else { + char key[25]; + snprintf(key, sizeof(key), ZEND_LONG_FMT, num_key); + ZEND_PUTS_EX(key); + } + ZEND_PUTS_EX("] => "); + zend_print_zval_r_ex(write_func, tmp, indent+PRINT_ZVAL_INDENT); + ZEND_PUTS_EX("\n"); + } ZEND_HASH_FOREACH_END(); + indent -= PRINT_ZVAL_INDENT; + for (i = 0; i < indent; i++) { + ZEND_PUTS_EX(" "); + } + ZEND_PUTS_EX(")\n"); +} +/* }}} */ + +static void print_flat_hash(HashTable *ht) /* {{{ */ +{ + zval *tmp; + zend_string *string_key; + zend_ulong num_key; + int i = 0; + + ZEND_HASH_FOREACH_KEY_VAL_IND(ht, num_key, string_key, tmp) { + if (i++ > 0) { + ZEND_PUTS(","); + } + ZEND_PUTS("["); + if (string_key) { + ZEND_WRITE(string_key->val, string_key->len); + } else { + zend_printf(ZEND_ULONG_FMT, num_key); + } + ZEND_PUTS("] => "); + zend_print_flat_zval_r(tmp); + } ZEND_HASH_FOREACH_END(); +} +/* }}} */ + +ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy) /* {{{ */ +{ + if (Z_TYPE_P(expr) == IS_STRING) { + return 0; + } else { + ZVAL_STR(expr_copy, _zval_get_string_func(expr)); + return 1; + } +} +/* }}} */ + +ZEND_API size_t zend_print_zval(zval *expr, int indent) /* {{{ */ +{ + return zend_print_zval_ex(zend_write, expr, indent); +} +/* }}} */ + +ZEND_API size_t zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent) /* {{{ */ +{ + zend_string *str = zval_get_string(expr); + size_t len = str->len; + + if (len != 0) { + write_func(str->val, len); + } + + zend_string_release(str); + return len; +} +/* }}} */ + +ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */ +{ + switch (Z_TYPE_P(expr)) { + case IS_ARRAY: + ZEND_PUTS("Array ("); + if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) && + ++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) { + ZEND_PUTS(" *RECURSION*"); + Z_ARRVAL_P(expr)->u.v.nApplyCount--; + return; + } + print_flat_hash(Z_ARRVAL_P(expr)); + ZEND_PUTS(")"); + if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) { + Z_ARRVAL_P(expr)->u.v.nApplyCount--; + } + break; + case IS_OBJECT: + { + HashTable *properties = NULL; + zend_string *class_name = Z_OBJ_HANDLER_P(expr, get_class_name)(Z_OBJ_P(expr)); + zend_printf("%s Object (", class_name->val); + zend_string_release(class_name); + + if (Z_OBJ_APPLY_COUNT_P(expr) > 0) { + ZEND_PUTS(" *RECURSION*"); + return; + } + + if (Z_OBJ_HANDLER_P(expr, get_properties)) { + properties = Z_OBJPROP_P(expr); + } + if (properties) { + Z_OBJ_INC_APPLY_COUNT_P(expr); + print_flat_hash(properties); + Z_OBJ_DEC_APPLY_COUNT_P(expr); + } + ZEND_PUTS(")"); + break; + } + default: + zend_print_variable(expr); + break; + } +} +/* }}} */ + +ZEND_API void zend_print_zval_r(zval *expr, int indent) /* {{{ */ +{ + zend_print_zval_r_ex(zend_write, expr, indent); +} +/* }}} */ + +ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int indent) /* {{{ */ +{ + ZVAL_DEREF(expr); + switch (Z_TYPE_P(expr)) { + case IS_ARRAY: + ZEND_PUTS_EX("Array\n"); + if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) && + ++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) { + ZEND_PUTS_EX(" *RECURSION*"); + Z_ARRVAL_P(expr)->u.v.nApplyCount--; + return; + } + print_hash(write_func, Z_ARRVAL_P(expr), indent, 0); + if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) { + Z_ARRVAL_P(expr)->u.v.nApplyCount--; + } + break; + case IS_OBJECT: + { + HashTable *properties; + int is_temp; + + zend_string *class_name = Z_OBJ_HANDLER_P(expr, get_class_name)(Z_OBJ_P(expr)); + ZEND_PUTS_EX(class_name->val); + zend_string_release(class_name); + + ZEND_PUTS_EX(" Object\n"); + if (Z_OBJ_APPLY_COUNT_P(expr) > 0) { + ZEND_PUTS_EX(" *RECURSION*"); + return; + } + if ((properties = Z_OBJDEBUG_P(expr, is_temp)) == NULL) { + break; + } + + Z_OBJ_INC_APPLY_COUNT_P(expr); + print_hash(write_func, properties, indent, 1); + Z_OBJ_DEC_APPLY_COUNT_P(expr); + + if (is_temp) { + zend_hash_destroy(properties); + FREE_HASHTABLE(properties); + } + break; + } + default: + zend_print_zval_ex(write_func, expr, indent); + break; + } +} +/* }}} */ + +static FILE *zend_fopen_wrapper(const char *filename, zend_string **opened_path) /* {{{ */ +{ + if (opened_path) { + *opened_path = zend_string_init(filename, strlen(filename), 0); + } + return fopen(filename, "rb"); +} +/* }}} */ + +#ifdef ZTS +static zend_bool short_tags_default = 1; +static uint32_t compiler_options_default = ZEND_COMPILE_DEFAULT; +#else +# define short_tags_default 1 +# define compiler_options_default ZEND_COMPILE_DEFAULT +#endif + +static void zend_set_default_compile_time_values(void) /* {{{ */ +{ + /* default compile-time values */ + CG(short_tags) = short_tags_default; + CG(compiler_options) = compiler_options_default; +} +/* }}} */ + +#ifdef ZEND_WIN32 +static void zend_get_windows_version_info(OSVERSIONINFOEX *osvi) /* {{{ */ +{ + ZeroMemory(osvi, sizeof(OSVERSIONINFOEX)); + osvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if(!GetVersionEx((OSVERSIONINFO *) osvi)) { + ZEND_ASSERT(0); /* Should not happen as sizeof is used. */ + } +} +/* }}} */ +#endif + +static void zend_init_exception_op(void) /* {{{ */ +{ + memset(EG(exception_op), 0, sizeof(EG(exception_op))); + EG(exception_op)[0].opcode = ZEND_HANDLE_EXCEPTION; + EG(exception_op)[0].op1_type = IS_UNUSED; + EG(exception_op)[0].op2_type = IS_UNUSED; + EG(exception_op)[0].result_type = IS_UNUSED; + ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)); + EG(exception_op)[1].opcode = ZEND_HANDLE_EXCEPTION; + EG(exception_op)[1].op1_type = IS_UNUSED; + EG(exception_op)[1].op2_type = IS_UNUSED; + EG(exception_op)[1].result_type = IS_UNUSED; + ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)+1); + EG(exception_op)[2].opcode = ZEND_HANDLE_EXCEPTION; + EG(exception_op)[2].op1_type = IS_UNUSED; + EG(exception_op)[2].op2_type = IS_UNUSED; + EG(exception_op)[2].result_type = IS_UNUSED; + ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)+2); +} +/* }}} */ + +static void zend_init_call_trampoline_op(void) /* {{{ */ +{ + memset(&EG(call_trampoline_op), 0, sizeof(EG(call_trampoline_op))); + EG(call_trampoline_op).opcode = ZEND_CALL_TRAMPOLINE; + EG(call_trampoline_op).op1_type = IS_UNUSED; + EG(call_trampoline_op).op2_type = IS_UNUSED; + EG(call_trampoline_op).result_type = IS_UNUSED; + ZEND_VM_SET_OPCODE_HANDLER(&EG(call_trampoline_op)); +} +/* }}} */ + +#ifdef ZTS +static void function_copy_ctor(zval *zv) +{ + zend_function *old_func = Z_FUNC_P(zv); + Z_FUNC_P(zv) = pemalloc(sizeof(zend_internal_function), 1); + memcpy(Z_FUNC_P(zv), old_func, sizeof(zend_internal_function)); + function_add_ref(Z_FUNC_P(zv)); +} + +static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{{ */ +{ + compiler_globals->compiled_filename = NULL; + + compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); + zend_hash_init_ex(compiler_globals->function_table, 1024, NULL, ZEND_FUNCTION_DTOR, 1, 0); + zend_hash_copy(compiler_globals->function_table, global_function_table, function_copy_ctor); + + compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); + zend_hash_init_ex(compiler_globals->class_table, 64, NULL, ZEND_CLASS_DTOR, 1, 0); + zend_hash_copy(compiler_globals->class_table, global_class_table, zend_class_add_ref); + + zend_set_default_compile_time_values(); + + compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable)); + zend_hash_init_ex(compiler_globals->auto_globals, 8, NULL, NULL, 1, 0); + zend_hash_copy(compiler_globals->auto_globals, global_auto_globals_table, NULL /* empty element */); + + compiler_globals->last_static_member = zend_hash_num_elements(compiler_globals->class_table); + if (compiler_globals->last_static_member) { + compiler_globals->static_members_table = calloc(compiler_globals->last_static_member, sizeof(zval*)); + } else { + compiler_globals->static_members_table = NULL; + } + compiler_globals->script_encoding_list = NULL; + +#ifdef ZTS + zend_interned_empty_string_init(&compiler_globals->empty_string); + + memset(compiler_globals->one_char_string, 0, sizeof(compiler_globals->one_char_string)); +#endif +} +/* }}} */ + +static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{{ */ +{ + if (compiler_globals->function_table != GLOBAL_FUNCTION_TABLE) { + zend_hash_destroy(compiler_globals->function_table); + free(compiler_globals->function_table); + } + if (compiler_globals->class_table != GLOBAL_CLASS_TABLE) { + zend_hash_destroy(compiler_globals->class_table); + free(compiler_globals->class_table); + } + if (compiler_globals->auto_globals != GLOBAL_AUTO_GLOBALS_TABLE) { + zend_hash_destroy(compiler_globals->auto_globals); + free(compiler_globals->auto_globals); + } + if (compiler_globals->static_members_table) { + free(compiler_globals->static_members_table); + } + if (compiler_globals->script_encoding_list) { + pefree((char*)compiler_globals->script_encoding_list, 1); + } + compiler_globals->last_static_member = 0; + +#ifdef ZTS + zend_interned_empty_string_free(&compiler_globals->empty_string); +#endif +} +/* }}} */ + +static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{{ */ +{ + ZEND_TSRMLS_CACHE_UPDATE(); + + zend_startup_constants(); + zend_copy_constants(EG(zend_constants), GLOBAL_CONSTANTS_TABLE); + zend_init_rsrc_plist(); + zend_init_exception_op(); + zend_init_call_trampoline_op(); + memset(&executor_globals->trampoline, 0, sizeof(zend_op_array)); + executor_globals->lambda_count = 0; + ZVAL_UNDEF(&executor_globals->user_error_handler); + ZVAL_UNDEF(&executor_globals->user_exception_handler); + executor_globals->in_autoload = NULL; + executor_globals->current_execute_data = NULL; + executor_globals->current_module = NULL; + executor_globals->exit_status = 0; +#if XPFPA_HAVE_CW + executor_globals->saved_fpu_cw = 0; +#endif + executor_globals->saved_fpu_cw_ptr = NULL; + executor_globals->active = 0; + executor_globals->bailout = NULL; + executor_globals->error_handling = EH_NORMAL; + executor_globals->exception_class = NULL; + executor_globals->exception = NULL; + executor_globals->objects_store.object_buckets = NULL; +#ifdef ZEND_WIN32 + zend_get_windows_version_info(&executor_globals->windows_version_info); +#endif +} +/* }}} */ + +static void executor_globals_dtor(zend_executor_globals *executor_globals) /* {{{ */ +{ +#ifdef ZTS + zend_ini_dtor(executor_globals->ini_directives); +#else + zend_ini_shutdown(); +#endif + if (&executor_globals->persistent_list != global_persistent_list) { + zend_destroy_rsrc_list(&executor_globals->persistent_list); + } + if (executor_globals->zend_constants != GLOBAL_CONSTANTS_TABLE) { + zend_hash_destroy(executor_globals->zend_constants); + free(executor_globals->zend_constants); + } +} +/* }}} */ + +static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ +{ + if (zend_copy_ini_directives() == SUCCESS) { + zend_ini_refresh_caches(ZEND_INI_STAGE_STARTUP); + } +} +/* }}} */ +#endif + +#if defined(__FreeBSD__) || defined(__DragonFly__) +/* FreeBSD and DragonFly floating point precision fix */ +#include +#endif + +static void ini_scanner_globals_ctor(zend_ini_scanner_globals *scanner_globals_p) /* {{{ */ +{ + memset(scanner_globals_p, 0, sizeof(*scanner_globals_p)); +} +/* }}} */ + +static void php_scanner_globals_ctor(zend_php_scanner_globals *scanner_globals_p) /* {{{ */ +{ + memset(scanner_globals_p, 0, sizeof(*scanner_globals_p)); +} +/* }}} */ + +void zend_init_opcodes_handlers(void); + +static void module_destructor_zval(zval *zv) /* {{{ */ +{ + zend_module_entry *module = (zend_module_entry*)Z_PTR_P(zv); + + module_destructor(module); + free(module); +} +/* }}} */ + +static void auto_global_dtor(zval *zv) /* {{{ */ +{ + free(Z_PTR_P(zv)); +} +/* }}} */ + +static zend_bool php_auto_globals_create_globals(zend_string *name) /* {{{ */ +{ + zval globals; + + ZVAL_ARR(&globals, &EG(symbol_table)); + Z_TYPE_INFO_P(&globals) = IS_ARRAY | (IS_TYPE_SYMBOLTABLE << Z_TYPE_FLAGS_SHIFT); + ZVAL_NEW_REF(&globals, &globals); + zend_hash_update(&EG(symbol_table), name, &globals); + return 0; +} +/* }}} */ + +int zend_startup(zend_utility_functions *utility_functions, char **extensions) /* {{{ */ +{ +#ifdef ZTS + zend_compiler_globals *compiler_globals; + zend_executor_globals *executor_globals; + extern ZEND_API ts_rsrc_id ini_scanner_globals_id; + extern ZEND_API ts_rsrc_id language_scanner_globals_id; + ZEND_TSRMLS_CACHE_UPDATE(); +#else + extern zend_ini_scanner_globals ini_scanner_globals; + extern zend_php_scanner_globals language_scanner_globals; +#endif + + start_memory_manager(); + + virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */ + +#if defined(__FreeBSD__) || defined(__DragonFly__) + /* FreeBSD and DragonFly floating point precision fix */ + fpsetmask(0); +#endif + + zend_startup_strtod(); + zend_startup_extensions_mechanism(); + + /* Set up utility functions and values */ + zend_error_cb = utility_functions->error_function; + zend_printf = utility_functions->printf_function; + zend_write = (zend_write_func_t) utility_functions->write_function; + zend_fopen = utility_functions->fopen_function; + if (!zend_fopen) { + zend_fopen = zend_fopen_wrapper; + } + zend_stream_open_function = utility_functions->stream_open_function; + zend_message_dispatcher_p = utility_functions->message_handler; +#ifndef ZEND_SIGNALS + zend_block_interruptions = utility_functions->block_interruptions; + zend_unblock_interruptions = utility_functions->unblock_interruptions; +#endif + zend_get_configuration_directive_p = utility_functions->get_configuration_directive; + zend_ticks_function = utility_functions->ticks_function; + zend_on_timeout = utility_functions->on_timeout; + zend_vspprintf = utility_functions->vspprintf_function; + zend_vstrpprintf = utility_functions->vstrpprintf_function; + zend_getenv = utility_functions->getenv_function; + zend_resolve_path = utility_functions->resolve_path_function; + +#if HAVE_DTRACE +/* build with dtrace support */ + zend_compile_file = dtrace_compile_file; + zend_execute_ex = dtrace_execute_ex; + zend_execute_internal = dtrace_execute_internal; +#else + zend_compile_file = compile_file; + zend_execute_ex = execute_ex; + zend_execute_internal = NULL; +#endif /* HAVE_SYS_SDT_H */ + zend_compile_string = compile_string; + zend_throw_exception_hook = NULL; + + /* Set up the default garbage collection implementation. */ + gc_collect_cycles = zend_gc_collect_cycles; + + zend_init_opcodes_handlers(); + + /* set up version */ + zend_version_info = strdup(ZEND_CORE_VERSION_INFO); + zend_version_info_length = sizeof(ZEND_CORE_VERSION_INFO) - 1; + + GLOBAL_FUNCTION_TABLE = (HashTable *) malloc(sizeof(HashTable)); + GLOBAL_CLASS_TABLE = (HashTable *) malloc(sizeof(HashTable)); + GLOBAL_AUTO_GLOBALS_TABLE = (HashTable *) malloc(sizeof(HashTable)); + GLOBAL_CONSTANTS_TABLE = (HashTable *) malloc(sizeof(HashTable)); + + zend_hash_init_ex(GLOBAL_FUNCTION_TABLE, 1024, NULL, ZEND_FUNCTION_DTOR, 1, 0); + zend_hash_init_ex(GLOBAL_CLASS_TABLE, 64, NULL, ZEND_CLASS_DTOR, 1, 0); + zend_hash_init_ex(GLOBAL_AUTO_GLOBALS_TABLE, 8, NULL, auto_global_dtor, 1, 0); + zend_hash_init_ex(GLOBAL_CONSTANTS_TABLE, 128, NULL, ZEND_CONSTANT_DTOR, 1, 0); + + zend_hash_init_ex(&module_registry, 32, NULL, module_destructor_zval, 1, 0); + zend_init_rsrc_list_dtors(); + +#ifdef ZTS + ts_allocate_id(&compiler_globals_id, sizeof(zend_compiler_globals), (ts_allocate_ctor) compiler_globals_ctor, (ts_allocate_dtor) compiler_globals_dtor); + ts_allocate_id(&executor_globals_id, sizeof(zend_executor_globals), (ts_allocate_ctor) executor_globals_ctor, (ts_allocate_dtor) executor_globals_dtor); + ts_allocate_id(&language_scanner_globals_id, sizeof(zend_php_scanner_globals), (ts_allocate_ctor) php_scanner_globals_ctor, NULL); + ts_allocate_id(&ini_scanner_globals_id, sizeof(zend_ini_scanner_globals), (ts_allocate_ctor) ini_scanner_globals_ctor, NULL); + compiler_globals = ts_resource(compiler_globals_id); + executor_globals = ts_resource(executor_globals_id); + + compiler_globals_dtor(compiler_globals); + compiler_globals->in_compilation = 0; + compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); + + *compiler_globals->function_table = *GLOBAL_FUNCTION_TABLE; + *compiler_globals->class_table = *GLOBAL_CLASS_TABLE; + compiler_globals->auto_globals = GLOBAL_AUTO_GLOBALS_TABLE; + + zend_hash_destroy(executor_globals->zend_constants); + *executor_globals->zend_constants = *GLOBAL_CONSTANTS_TABLE; +#else + ini_scanner_globals_ctor(&ini_scanner_globals); + php_scanner_globals_ctor(&language_scanner_globals); + zend_set_default_compile_time_values(); +#ifdef ZEND_WIN32 + zend_get_windows_version_info(&EG(windows_version_info)); +#endif +#endif + EG(error_reporting) = E_ALL & ~E_NOTICE; + + zend_interned_strings_init(); + zend_startup_builtin_functions(); + zend_register_standard_constants(); + zend_register_auto_global(zend_string_init("GLOBALS", sizeof("GLOBALS") - 1, 1), 1, php_auto_globals_create_globals); + +#ifndef ZTS + zend_init_rsrc_plist(); + zend_init_exception_op(); + zend_init_call_trampoline_op(); +#endif + + zend_ini_startup(); + +#ifdef ZTS + tsrm_set_new_thread_end_handler(zend_new_thread_end_handler); +#endif + +#ifdef ZEND_SIGNALS + zend_signal_startup(); +#endif + + return SUCCESS; +} +/* }}} */ + +void zend_register_standard_ini_entries(void) /* {{{ */ +{ + int module_number = 0; + + REGISTER_INI_ENTRIES(); +} +/* }}} */ + +/* Unlink the global (r/o) copies of the class, function and constant tables, + * and use a fresh r/w copy for the startup thread + */ +void zend_post_startup(void) /* {{{ */ +{ +#ifdef ZTS + zend_encoding **script_encoding_list; + + zend_compiler_globals *compiler_globals = ts_resource(compiler_globals_id); + zend_executor_globals *executor_globals = ts_resource(executor_globals_id); + + *GLOBAL_FUNCTION_TABLE = *compiler_globals->function_table; + *GLOBAL_CLASS_TABLE = *compiler_globals->class_table; + *GLOBAL_CONSTANTS_TABLE = *executor_globals->zend_constants; + + short_tags_default = CG(short_tags); + compiler_options_default = CG(compiler_options); + + zend_destroy_rsrc_list(&EG(persistent_list)); + free(compiler_globals->function_table); + free(compiler_globals->class_table); + if ((script_encoding_list = (zend_encoding **)compiler_globals->script_encoding_list)) { + compiler_globals_ctor(compiler_globals); + compiler_globals->script_encoding_list = (const zend_encoding **)script_encoding_list; + } else { + compiler_globals_ctor(compiler_globals); + } + free(EG(zend_constants)); + + virtual_cwd_deactivate(); + + executor_globals_ctor(executor_globals); + global_persistent_list = &EG(persistent_list); + zend_copy_ini_directives(); +#else + virtual_cwd_deactivate(); +#endif +} +/* }}} */ + +void zend_shutdown(void) /* {{{ */ +{ + zend_destroy_rsrc_list(&EG(persistent_list)); + if (EG(active)) + { + /* + * The order of destruction is important here. + * See bugs #65463 and 66036. + */ + zend_function *func; + zend_class_entry *ce; + + ZEND_HASH_REVERSE_FOREACH_PTR(GLOBAL_FUNCTION_TABLE, func) { + if (func->type == ZEND_USER_FUNCTION) { + zend_cleanup_op_array_data((zend_op_array *) func); + } + } ZEND_HASH_FOREACH_END(); + ZEND_HASH_REVERSE_FOREACH_PTR(GLOBAL_CLASS_TABLE, ce) { + if (ce->type == ZEND_USER_CLASS) { + zend_cleanup_user_class_data(ce); + } else { + break; + } + } ZEND_HASH_FOREACH_END(); + zend_cleanup_internal_classes(); + zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) clean_non_persistent_function_full); + zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) clean_non_persistent_class_full); + } + zend_destroy_modules(); + + virtual_cwd_deactivate(); + virtual_cwd_shutdown(); + + zend_hash_destroy(GLOBAL_FUNCTION_TABLE); + zend_hash_destroy(GLOBAL_CLASS_TABLE); + + zend_hash_destroy(GLOBAL_AUTO_GLOBALS_TABLE); + free(GLOBAL_AUTO_GLOBALS_TABLE); + + zend_shutdown_extensions(); + free(zend_version_info); + + free(GLOBAL_FUNCTION_TABLE); + free(GLOBAL_CLASS_TABLE); + + zend_hash_destroy(GLOBAL_CONSTANTS_TABLE); + free(GLOBAL_CONSTANTS_TABLE); + zend_shutdown_strtod(); + +#ifdef ZTS + GLOBAL_FUNCTION_TABLE = NULL; + GLOBAL_CLASS_TABLE = NULL; + GLOBAL_AUTO_GLOBALS_TABLE = NULL; + GLOBAL_CONSTANTS_TABLE = NULL; +#endif + zend_destroy_rsrc_list_dtors(); + + zend_interned_strings_dtor(); +} +/* }}} */ + +void zend_set_utility_values(zend_utility_values *utility_values) /* {{{ */ +{ + zend_uv = *utility_values; + zend_uv.import_use_extension_length = (uint)strlen(zend_uv.import_use_extension); +} +/* }}} */ + +/* this should be compatible with the standard zenderror */ +void zenderror(const char *error) /* {{{ */ +{ + if (EG(exception)) { + /* An exception was thrown in the lexer, don't throw another in the parser. */ + return; + } + + zend_throw_exception(zend_get_parse_exception(), error, E_PARSE); +} +/* }}} */ + +BEGIN_EXTERN_C() +ZEND_API void _zend_bailout(char *filename, uint lineno) /* {{{ */ +{ + + if (!EG(bailout)) { + zend_output_debug_string(1, "%s(%d) : Bailed out without a bailout address!", filename, lineno); + exit(-1); + } + CG(unclean_shutdown) = 1; + CG(active_class_entry) = NULL; + CG(in_compilation) = 0; + EG(current_execute_data) = NULL; + LONGJMP(*EG(bailout), FAILURE); +} +/* }}} */ +END_EXTERN_C() + +ZEND_API void zend_append_version_info(const zend_extension *extension) /* {{{ */ +{ + char *new_info; + uint new_info_length; + + new_info_length = (uint)(sizeof(" with v, , by \n") + + strlen(extension->name) + + strlen(extension->version) + + strlen(extension->copyright) + + strlen(extension->author)); + + new_info = (char *) malloc(new_info_length + 1); + + snprintf(new_info, new_info_length, " with %s v%s, %s, by %s\n", extension->name, extension->version, extension->copyright, extension->author); + + zend_version_info = (char *) realloc(zend_version_info, zend_version_info_length+new_info_length + 1); + strncat(zend_version_info, new_info, new_info_length); + zend_version_info_length += new_info_length; + free(new_info); +} +/* }}} */ + +ZEND_API char *get_zend_version(void) /* {{{ */ +{ + return zend_version_info; +} +/* }}} */ + +ZEND_API void zend_activate(void) /* {{{ */ +{ +#ifdef ZTS + virtual_cwd_activate(); +#endif + gc_reset(); + init_compiler(); + init_executor(); + startup_scanner(); +} +/* }}} */ + +void zend_call_destructors(void) /* {{{ */ +{ + zend_try { + shutdown_destructors(); + } zend_end_try(); +} +/* }}} */ + +ZEND_API void zend_deactivate(void) /* {{{ */ +{ + /* we're no longer executing anything */ + EG(current_execute_data) = NULL; + + zend_try { + shutdown_scanner(); + } zend_end_try(); + + /* shutdown_executor() takes care of its own bailout handling */ + shutdown_executor(); + + zend_try { + shutdown_compiler(); + } zend_end_try(); + + zend_destroy_rsrc_list(&EG(regular_list)); + +#if GC_BENCH + fprintf(stderr, "GC Statistics\n"); + fprintf(stderr, "-------------\n"); + fprintf(stderr, "Runs: %d\n", GC_G(gc_runs)); + fprintf(stderr, "Collected: %d\n", GC_G(collected)); + fprintf(stderr, "Root buffer length: %d\n", GC_G(root_buf_length)); + fprintf(stderr, "Root buffer peak: %d\n\n", GC_G(root_buf_peak)); + fprintf(stderr, " Possible Remove from Marked\n"); + fprintf(stderr, " Root Buffered buffer grey\n"); + fprintf(stderr, " -------- -------- ----------- ------\n"); + fprintf(stderr, "ZVAL %8d %8d %9d %8d\n", GC_G(zval_possible_root), GC_G(zval_buffered), GC_G(zval_remove_from_buffer), GC_G(zval_marked_grey)); + fprintf(stderr, "ZOBJ %8d %8d %9d %8d\n", GC_G(zobj_possible_root), GC_G(zobj_buffered), GC_G(zobj_remove_from_buffer), GC_G(zobj_marked_grey)); +#endif + + zend_try { + zend_ini_deactivate(); + } zend_end_try(); +} +/* }}} */ + +BEGIN_EXTERN_C() +ZEND_API void zend_message_dispatcher(zend_long message, const void *data) /* {{{ */ +{ + if (zend_message_dispatcher_p) { + zend_message_dispatcher_p(message, data); + } +} +/* }}} */ +END_EXTERN_C() + +ZEND_API zval *zend_get_configuration_directive(zend_string *name) /* {{{ */ +{ + if (zend_get_configuration_directive_p) { + return zend_get_configuration_directive_p(name); + } else { + return NULL; + } +} +/* }}} */ + +#define SAVE_STACK(stack) do { \ + if (CG(stack).top) { \ + memcpy(&stack, &CG(stack), sizeof(zend_stack)); \ + CG(stack).top = CG(stack).max = 0; \ + CG(stack).elements = NULL; \ + } else { \ + stack.top = 0; \ + } \ + } while (0) + +#define RESTORE_STACK(stack) do { \ + if (stack.top) { \ + zend_stack_destroy(&CG(stack)); \ + memcpy(&CG(stack), &stack, sizeof(zend_stack)); \ + } \ + } while (0) + +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) +ZEND_API void zend_error(int type, const char *format, ...) /* {{{ */ +#else +static void zend_error_va_list(int type, const char *format, va_list args) +#endif +{ + char *str; + int len; +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_list args; +#endif + va_list usr_copy; + zval params[5]; + zval retval; + const char *error_filename; + uint error_lineno = 0; + zval orig_user_error_handler; + zend_bool in_compilation; + zend_class_entry *saved_class_entry; + zend_stack loop_var_stack; + zend_stack delayed_oplines_stack; + zend_array *symbol_table; + + if (type & E_EXCEPTION) { + type &= ~E_EXCEPTION; + //TODO: we can't convert compile-time errors to exceptions yet??? + if (EG(current_execute_data) && !CG(in_compilation)) { + char *message = NULL; + +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_start(args, format); +#endif + zend_vspprintf(&message, 0, format, args); + zend_throw_exception(zend_get_engine_exception(), message, type); + efree(message); +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_end(args); +#endif + return; + } + } + + /* Report about uncaught exception in case of fatal errors */ + if (EG(exception)) { + zend_execute_data *ex; + const zend_op *opline; + + switch (type) { + case E_CORE_ERROR: + case E_ERROR: + case E_RECOVERABLE_ERROR: + case E_PARSE: + case E_COMPILE_ERROR: + case E_USER_ERROR: + ex = EG(current_execute_data); + opline = NULL; + while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) { + ex = ex->prev_execute_data; + } + if (ex && ex->opline->opcode == ZEND_HANDLE_EXCEPTION && + EG(opline_before_exception)) { + opline = EG(opline_before_exception); + } + zend_exception_error(EG(exception), E_WARNING); + EG(exception) = NULL; + if (opline) { + ex->opline = opline; + } + break; + default: + break; + } + } + + /* Obtain relevant filename and lineno */ + switch (type) { + case E_CORE_ERROR: + case E_CORE_WARNING: + error_filename = NULL; + error_lineno = 0; + break; + case E_PARSE: + case E_COMPILE_ERROR: + case E_COMPILE_WARNING: + case E_ERROR: + case E_NOTICE: + case E_STRICT: + case E_DEPRECATED: + case E_WARNING: + case E_USER_ERROR: + case E_USER_WARNING: + case E_USER_NOTICE: + case E_USER_DEPRECATED: + case E_RECOVERABLE_ERROR: + if (zend_is_compiling()) { + error_filename = zend_get_compiled_filename()->val; + error_lineno = zend_get_compiled_lineno(); + } else if (zend_is_executing()) { + error_filename = zend_get_executed_filename(); + if (error_filename[0] == '[') { /* [no active file] */ + error_filename = NULL; + error_lineno = 0; + } else { + error_lineno = zend_get_executed_lineno(); + } + } else { + error_filename = NULL; + error_lineno = 0; + } + break; + default: + error_filename = NULL; + error_lineno = 0; + break; + } + if (!error_filename) { + error_filename = "Unknown"; + } + +#ifdef HAVE_DTRACE + if (DTRACE_ERROR_ENABLED()) { + char *dtrace_error_buffer; +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_start(args, format); +#endif + zend_vspprintf(&dtrace_error_buffer, 0, format, args); + DTRACE_ERROR(dtrace_error_buffer, (char *)error_filename, error_lineno); + efree(dtrace_error_buffer); +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_end(args); +#endif + } +#endif /* HAVE_DTRACE */ + +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_start(args, format); +#endif + + /* if we don't have a user defined error handler */ + if (Z_TYPE(EG(user_error_handler)) == IS_UNDEF + || !(EG(user_error_handler_error_reporting) & type) + || EG(error_handling) != EH_NORMAL) { + zend_error_cb(type, error_filename, error_lineno, format, args); + } else switch (type) { + case E_ERROR: + case E_PARSE: + case E_CORE_ERROR: + case E_CORE_WARNING: + case E_COMPILE_ERROR: + case E_COMPILE_WARNING: + /* The error may not be safe to handle in user-space */ + zend_error_cb(type, error_filename, error_lineno, format, args); + break; + default: + /* Handle the error in user space */ +/* va_copy() is __va_copy() in old gcc versions. + * According to the autoconf manual, using + * memcpy(&dst, &src, sizeof(va_list)) + * gives maximum portability. */ +#ifndef va_copy +# ifdef __va_copy +# define va_copy(dest, src) __va_copy((dest), (src)) +# else +# define va_copy(dest, src) memcpy(&(dest), &(src), sizeof(va_list)) +# endif +#endif + va_copy(usr_copy, args); + len = (int)zend_vspprintf(&str, 0, format, usr_copy); + ZVAL_NEW_STR(¶ms[1], zend_string_init(str, len, 0)); + efree(str); +#ifdef va_copy + va_end(usr_copy); +#endif + + ZVAL_LONG(¶ms[0], type); + + if (error_filename) { + ZVAL_STRING(¶ms[2], error_filename); + } else { + ZVAL_NULL(¶ms[2]); + } + + ZVAL_LONG(¶ms[3], error_lineno); + + symbol_table = zend_rebuild_symbol_table(); + + /* during shutdown the symbol table table can be still null */ + if (!symbol_table) { + ZVAL_NULL(¶ms[4]); + } else { + ZVAL_ARR(¶ms[4], zend_array_dup(symbol_table)); + } + + ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler)); + ZVAL_UNDEF(&EG(user_error_handler)); + + /* User error handler may include() additinal PHP files. + * If an error was generated during comilation PHP will compile + * such scripts recursivly, but some CG() variables may be + * inconsistent. */ + + in_compilation = CG(in_compilation); + if (in_compilation) { + saved_class_entry = CG(active_class_entry); + CG(active_class_entry) = NULL; + SAVE_STACK(loop_var_stack); + SAVE_STACK(delayed_oplines_stack); + CG(in_compilation) = 0; + } + + if (call_user_function_ex(CG(function_table), NULL, &orig_user_error_handler, &retval, 5, params, 1, NULL) == SUCCESS) { + if (Z_TYPE(retval) != IS_UNDEF) { + if (Z_TYPE(retval) == IS_FALSE) { + zend_error_cb(type, error_filename, error_lineno, format, args); + } + zval_ptr_dtor(&retval); + } + } else if (!EG(exception)) { + /* The user error handler failed, use built-in error handler */ + zend_error_cb(type, error_filename, error_lineno, format, args); + } + + if (in_compilation) { + CG(active_class_entry) = saved_class_entry; + RESTORE_STACK(loop_var_stack); + RESTORE_STACK(delayed_oplines_stack); + CG(in_compilation) = 1; + } + + zval_ptr_dtor(¶ms[4]); + zval_ptr_dtor(¶ms[3]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[0]); + + if (Z_TYPE(EG(user_error_handler)) == IS_UNDEF) { + ZVAL_COPY_VALUE(&EG(user_error_handler), &orig_user_error_handler); + } else { + zval_ptr_dtor(&orig_user_error_handler); + } + break; + } + +#if !defined(HAVE_NORETURN) || defined(HAVE_NORETURN_ALIAS) + va_end(args); +#endif + + if (type == E_PARSE) { + /* eval() errors do not affect exit_status */ + if (!(EG(current_execute_data) && + EG(current_execute_data)->func && + ZEND_USER_CODE(EG(current_execute_data)->func->type) && + EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL && + EG(current_execute_data)->opline->extended_value == ZEND_EVAL)) { + EG(exit_status) = 255; + } + } +} +/* }}} */ + +#ifdef HAVE_NORETURN +# ifdef HAVE_NORETURN_ALIAS +void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((alias("zend_error"),noreturn)); +# else +ZEND_API void zend_error(int type, const char *format, ...) /* {{{ */ +{ + va_list va; + + va_start(va, format); + zend_error_va_list(type, format, va); + va_end(va); +} + +ZEND_API ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) +{ + va_list va; + + va_start(va, format); + zend_error_va_list(type, format, va); + va_end(va); +} +/* }}} */ +# endif +#endif + +ZEND_API void zend_type_error(const char *format, ...) /* {{{ */ +{ + va_list va; + char *message = NULL; + + va_start(va, format); + zend_vspprintf(&message, 0, format, va); + zend_throw_exception(zend_get_type_exception(), message, E_ERROR); + efree(message); + va_end(va); +} /* }}} */ + +ZEND_API void zend_internal_type_error(zend_bool throw_exception, const char *format, ...) /* {{{ */ +{ + va_list va; + char *message = NULL; + + va_start(va, format); + zend_vspprintf(&message, 0, format, va); + if (throw_exception) { + zend_throw_exception(zend_get_type_exception(), message, E_ERROR); + } else { + zend_error(E_WARNING, message); + } + efree(message); + + va_end(va); +} /* }}} */ + +ZEND_API void zend_output_debug_string(zend_bool trigger_break, const char *format, ...) /* {{{ */ +{ +#if ZEND_DEBUG + va_list args; + + va_start(args, format); +# ifdef ZEND_WIN32 + { + char output_buf[1024]; + + vsnprintf(output_buf, 1024, format, args); + OutputDebugString(output_buf); + OutputDebugString("\n"); + if (trigger_break && IsDebuggerPresent()) { + DebugBreak(); + } + } +# else + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); +# endif + va_end(args); +#endif +} +/* }}} */ + +ZEND_API int zend_execute_scripts(int type, zval *retval, int file_count, ...) /* {{{ */ +{ + va_list files; + int i; + zend_file_handle *file_handle; + zend_op_array *op_array; + + va_start(files, file_count); + for (i = 0; i < file_count; i++) { + file_handle = va_arg(files, zend_file_handle *); + if (!file_handle) { + continue; + } + + op_array = zend_compile_file(file_handle, type); + if (file_handle->opened_path) { + zend_hash_add_empty_element(&EG(included_files), file_handle->opened_path); + } + zend_destroy_file_handle(file_handle); + if (op_array) { + zend_execute(op_array, retval); + zend_exception_restore(); + if (EG(exception)) { + if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { + zval orig_user_exception_handler; + zval params[1], retval2; + zend_object *old_exception; + old_exception = EG(exception); + EG(exception) = NULL; + ZVAL_OBJ(¶ms[0], old_exception); + ZVAL_COPY_VALUE(&orig_user_exception_handler, &EG(user_exception_handler)); + + if (call_user_function_ex(CG(function_table), NULL, &orig_user_exception_handler, &retval2, 1, params, 1, NULL) == SUCCESS) { + zval_ptr_dtor(&retval2); + if (EG(exception)) { + OBJ_RELEASE(EG(exception)); + EG(exception) = NULL; + } + OBJ_RELEASE(old_exception); + } else { + EG(exception) = old_exception; + zend_exception_error(EG(exception), E_ERROR); + } + } else { + zend_exception_error(EG(exception), E_ERROR); + } + } + destroy_op_array(op_array); + efree_size(op_array, sizeof(zend_op_array)); + } else if (type==ZEND_REQUIRE) { + va_end(files); + return FAILURE; + } + } + va_end(files); + + return SUCCESS; +} +/* }}} */ + +#define COMPILED_STRING_DESCRIPTION_FORMAT "%s(%d) : %s" + +ZEND_API char *zend_make_compiled_string_description(const char *name) /* {{{ */ +{ + const char *cur_filename; + int cur_lineno; + char *compiled_string_description; + + if (zend_is_compiling()) { + cur_filename = zend_get_compiled_filename()->val; + cur_lineno = zend_get_compiled_lineno(); + } else if (zend_is_executing()) { + cur_filename = zend_get_executed_filename(); + cur_lineno = zend_get_executed_lineno(); + } else { + cur_filename = "Unknown"; + cur_lineno = 0; + } + + zend_spprintf(&compiled_string_description, 0, COMPILED_STRING_DESCRIPTION_FORMAT, cur_filename, cur_lineno, name); + return compiled_string_description; +} +/* }}} */ + +void free_estring(char **str_p) /* {{{ */ +{ + efree(*str_p); +} +/* }}} */ + +void free_string_zval(zval *zv) /* {{{ */ +{ + zend_string *str = Z_PTR_P(zv); + zend_string_release(str); +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */