gmp.c 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Stanislav Malyshev <stas@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include "php.h"
  22. #include "php_ini.h"
  23. #include "php_gmp.h"
  24. #include "ext/standard/info.h"
  25. #include "ext/standard/php_var.h"
  26. #include "ext/standard/php_smart_str_public.h"
  27. #include "zend_exceptions.h"
  28. #if HAVE_GMP
  29. #include <gmp.h>
  30. /* Needed for gmp_random() */
  31. #include "ext/standard/php_rand.h"
  32. #include "ext/standard/php_lcg.h"
  33. #define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
  34. /* {{{ arginfo */
  35. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_init, 0, 0, 1)
  36. ZEND_ARG_INFO(0, number)
  37. ZEND_ARG_INFO(0, base)
  38. ZEND_END_ARG_INFO()
  39. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_import, 0, 0, 1)
  40. ZEND_ARG_INFO(0, data)
  41. ZEND_ARG_INFO(0, word_size)
  42. ZEND_ARG_INFO(0, options)
  43. ZEND_END_ARG_INFO()
  44. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_export, 0, 0, 1)
  45. ZEND_ARG_INFO(0, gmpnumber)
  46. ZEND_ARG_INFO(0, word_size)
  47. ZEND_ARG_INFO(0, options)
  48. ZEND_END_ARG_INFO()
  49. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_intval, 0, 0, 1)
  50. ZEND_ARG_INFO(0, gmpnumber)
  51. ZEND_END_ARG_INFO()
  52. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_strval, 0, 0, 1)
  53. ZEND_ARG_INFO(0, gmpnumber)
  54. ZEND_ARG_INFO(0, base)
  55. ZEND_END_ARG_INFO()
  56. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_unary, 0, 0, 1)
  57. ZEND_ARG_INFO(0, a)
  58. ZEND_END_ARG_INFO()
  59. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_binary, 0, 0, 2)
  60. ZEND_ARG_INFO(0, a)
  61. ZEND_ARG_INFO(0, b)
  62. ZEND_END_ARG_INFO()
  63. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div, 0, 0, 2)
  64. ZEND_ARG_INFO(0, a)
  65. ZEND_ARG_INFO(0, b)
  66. ZEND_ARG_INFO(0, round)
  67. ZEND_END_ARG_INFO()
  68. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_pow, 0, 0, 2)
  69. ZEND_ARG_INFO(0, base)
  70. ZEND_ARG_INFO(0, exp)
  71. ZEND_END_ARG_INFO()
  72. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_powm, 0, 0, 3)
  73. ZEND_ARG_INFO(0, base)
  74. ZEND_ARG_INFO(0, exp)
  75. ZEND_ARG_INFO(0, mod)
  76. ZEND_END_ARG_INFO()
  77. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_root, 0, 0, 2)
  78. ZEND_ARG_INFO(0, a)
  79. ZEND_ARG_INFO(0, nth)
  80. ZEND_END_ARG_INFO()
  81. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_prob_prime, 0, 0, 1)
  82. ZEND_ARG_INFO(0, a)
  83. ZEND_ARG_INFO(0, reps)
  84. ZEND_END_ARG_INFO()
  85. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random, 0, 0, 0)
  86. ZEND_ARG_INFO(0, limiter)
  87. ZEND_END_ARG_INFO()
  88. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_bits, 0, 0, 1)
  89. ZEND_ARG_INFO(0, bits)
  90. ZEND_END_ARG_INFO()
  91. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_range, 0, 0, 2)
  92. ZEND_ARG_INFO(0, min)
  93. ZEND_ARG_INFO(0, max)
  94. ZEND_END_ARG_INFO()
  95. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_setbit, 0, 0, 2)
  96. ZEND_ARG_INFO(0, a)
  97. ZEND_ARG_INFO(0, index)
  98. ZEND_ARG_INFO(0, set_clear)
  99. ZEND_END_ARG_INFO()
  100. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_bit, 0, 0, 2)
  101. ZEND_ARG_INFO(0, a)
  102. ZEND_ARG_INFO(0, index)
  103. ZEND_END_ARG_INFO()
  104. ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_scan, 0, 0, 2)
  105. ZEND_ARG_INFO(0, a)
  106. ZEND_ARG_INFO(0, start)
  107. ZEND_END_ARG_INFO()
  108. /* }}} */
  109. ZEND_DECLARE_MODULE_GLOBALS(gmp)
  110. static ZEND_GINIT_FUNCTION(gmp);
  111. /* {{{ gmp_functions[]
  112. */
  113. const zend_function_entry gmp_functions[] = {
  114. ZEND_FE(gmp_init, arginfo_gmp_init)
  115. ZEND_FE(gmp_import, arginfo_gmp_import)
  116. ZEND_FE(gmp_export, arginfo_gmp_export)
  117. ZEND_FE(gmp_intval, arginfo_gmp_intval)
  118. ZEND_FE(gmp_strval, arginfo_gmp_strval)
  119. ZEND_FE(gmp_add, arginfo_gmp_binary)
  120. ZEND_FE(gmp_sub, arginfo_gmp_binary)
  121. ZEND_FE(gmp_mul, arginfo_gmp_binary)
  122. ZEND_FE(gmp_div_qr, arginfo_gmp_div)
  123. ZEND_FE(gmp_div_q, arginfo_gmp_div)
  124. ZEND_FE(gmp_div_r, arginfo_gmp_div)
  125. ZEND_FALIAS(gmp_div, gmp_div_q, arginfo_gmp_div)
  126. ZEND_FE(gmp_mod, arginfo_gmp_binary)
  127. ZEND_FE(gmp_divexact, arginfo_gmp_binary)
  128. ZEND_FE(gmp_neg, arginfo_gmp_unary)
  129. ZEND_FE(gmp_abs, arginfo_gmp_unary)
  130. ZEND_FE(gmp_fact, arginfo_gmp_unary)
  131. ZEND_FE(gmp_sqrt, arginfo_gmp_unary)
  132. ZEND_FE(gmp_sqrtrem, arginfo_gmp_unary)
  133. ZEND_FE(gmp_root, arginfo_gmp_root)
  134. ZEND_FE(gmp_rootrem, arginfo_gmp_root)
  135. ZEND_FE(gmp_pow, arginfo_gmp_pow)
  136. ZEND_FE(gmp_powm, arginfo_gmp_powm)
  137. ZEND_FE(gmp_perfect_square, arginfo_gmp_unary)
  138. ZEND_FE(gmp_prob_prime, arginfo_gmp_prob_prime)
  139. ZEND_FE(gmp_gcd, arginfo_gmp_binary)
  140. ZEND_FE(gmp_gcdext, arginfo_gmp_binary)
  141. ZEND_FE(gmp_invert, arginfo_gmp_binary)
  142. ZEND_FE(gmp_jacobi, arginfo_gmp_binary)
  143. ZEND_FE(gmp_legendre, arginfo_gmp_binary)
  144. ZEND_FE(gmp_cmp, arginfo_gmp_binary)
  145. ZEND_FE(gmp_sign, arginfo_gmp_unary)
  146. ZEND_FE(gmp_random, arginfo_gmp_random)
  147. ZEND_FE(gmp_random_bits, arginfo_gmp_random_bits)
  148. ZEND_FE(gmp_random_range, arginfo_gmp_random_range)
  149. ZEND_FE(gmp_and, arginfo_gmp_binary)
  150. ZEND_FE(gmp_or, arginfo_gmp_binary)
  151. ZEND_FE(gmp_com, arginfo_gmp_unary)
  152. ZEND_FE(gmp_xor, arginfo_gmp_binary)
  153. ZEND_FE(gmp_setbit, arginfo_gmp_setbit)
  154. ZEND_FE(gmp_clrbit, arginfo_gmp_bit)
  155. ZEND_FE(gmp_testbit, arginfo_gmp_bit)
  156. ZEND_FE(gmp_scan0, arginfo_gmp_scan)
  157. ZEND_FE(gmp_scan1, arginfo_gmp_scan)
  158. ZEND_FE(gmp_popcount, arginfo_gmp_unary)
  159. ZEND_FE(gmp_hamdist, arginfo_gmp_binary)
  160. ZEND_FE(gmp_nextprime, arginfo_gmp_unary)
  161. PHP_FE_END
  162. };
  163. /* }}} */
  164. /* {{{ gmp_module_entry
  165. */
  166. zend_module_entry gmp_module_entry = {
  167. STANDARD_MODULE_HEADER,
  168. "gmp",
  169. gmp_functions,
  170. ZEND_MODULE_STARTUP_N(gmp),
  171. NULL,
  172. NULL,
  173. ZEND_MODULE_DEACTIVATE_N(gmp),
  174. ZEND_MODULE_INFO_N(gmp),
  175. NO_VERSION_YET,
  176. ZEND_MODULE_GLOBALS(gmp),
  177. ZEND_GINIT(gmp),
  178. NULL,
  179. NULL,
  180. STANDARD_MODULE_PROPERTIES_EX
  181. };
  182. /* }}} */
  183. #ifdef COMPILE_DL_GMP
  184. ZEND_GET_MODULE(gmp)
  185. #endif
  186. zend_class_entry *gmp_ce;
  187. static zend_object_handlers gmp_object_handlers;
  188. typedef struct _gmp_object {
  189. zend_object std;
  190. mpz_t num;
  191. } gmp_object;
  192. typedef struct _gmp_temp {
  193. mpz_t num;
  194. zend_bool is_used;
  195. } gmp_temp_t;
  196. #define GMP_ROUND_ZERO 0
  197. #define GMP_ROUND_PLUSINF 1
  198. #define GMP_ROUND_MINUSINF 2
  199. #define GMP_MSW_FIRST (1 << 0)
  200. #define GMP_LSW_FIRST (1 << 1)
  201. #define GMP_LITTLE_ENDIAN (1 << 2)
  202. #define GMP_BIG_ENDIAN (1 << 3)
  203. #define GMP_NATIVE_ENDIAN (1 << 4)
  204. #define GMP_42_OR_NEWER \
  205. ((__GNU_MP_VERSION >= 5) || (__GNU_MP_VERSION >= 4 && __GNU_MP_VERSION_MINOR >= 2))
  206. #define GMP_51_OR_NEWER \
  207. ((__GNU_MP_VERSION >= 6) || (__GNU_MP_VERSION >= 5 && __GNU_MP_VERSION_MINOR >= 1))
  208. /* The maximum base for input and output conversions is 62 from GMP 4.2
  209. * onwards. */
  210. #if GMP_42_OR_NEWER
  211. # define MAX_BASE 62
  212. #else
  213. # define MAX_BASE 36
  214. #endif
  215. #define IS_GMP(zval) \
  216. (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), gmp_ce TSRMLS_CC))
  217. #define GET_GMP_FROM_ZVAL(zval) \
  218. (((gmp_object *) zend_object_store_get_object((zval) TSRMLS_CC))->num)
  219. /* The FETCH_GMP_ZVAL_* family of macros is used to fetch a gmp number
  220. * (mpz_ptr) from a zval. If the zval is not a GMP instance, then we
  221. * try to convert the value to a temporary gmp number using convert_to_gmp.
  222. * This temporary number is stored in the temp argument, which is of type
  223. * gmp_temp_t. This temporary value needs to be freed lateron using the
  224. * FREE_GMP_TEMP macro.
  225. *
  226. * If the conversion to a gmp number fails, the macros return false.
  227. * The _DEP / _DEP_DEP variants additionally free the temporary values
  228. * passed in the last / last two arguments.
  229. *
  230. * If one zval can sometimes be fetched as a long you have to set the
  231. * is_used member of the corresponding gmp_temp_t value to 0, otherwise
  232. * the FREE_GMP_TEMP and *_DEP macros will not work properly.
  233. *
  234. * The three FETCH_GMP_ZVAL_* macros below are mostly copy & paste code
  235. * as I couldn't find a way to combine them.
  236. */
  237. #define FREE_GMP_TEMP(temp) \
  238. if (temp.is_used) { \
  239. mpz_clear(temp.num); \
  240. }
  241. #define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2) \
  242. if (IS_GMP(zval)) { \
  243. gmpnumber = GET_GMP_FROM_ZVAL(zval); \
  244. temp.is_used = 0; \
  245. } else { \
  246. mpz_init(temp.num); \
  247. if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \
  248. mpz_clear(temp.num); \
  249. FREE_GMP_TEMP(dep1); \
  250. FREE_GMP_TEMP(dep2); \
  251. RETURN_FALSE; \
  252. } \
  253. temp.is_used = 1; \
  254. gmpnumber = temp.num; \
  255. }
  256. #define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep) \
  257. if (IS_GMP(zval)) { \
  258. gmpnumber = GET_GMP_FROM_ZVAL(zval); \
  259. temp.is_used = 0; \
  260. } else { \
  261. mpz_init(temp.num); \
  262. if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \
  263. mpz_clear(temp.num); \
  264. FREE_GMP_TEMP(dep); \
  265. RETURN_FALSE; \
  266. } \
  267. temp.is_used = 1; \
  268. gmpnumber = temp.num; \
  269. }
  270. #define FETCH_GMP_ZVAL(gmpnumber, zval, temp) \
  271. if (IS_GMP(zval)) { \
  272. gmpnumber = GET_GMP_FROM_ZVAL(zval); \
  273. temp.is_used = 0; \
  274. } else { \
  275. mpz_init(temp.num); \
  276. if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \
  277. mpz_clear(temp.num); \
  278. RETURN_FALSE; \
  279. } \
  280. temp.is_used = 1; \
  281. gmpnumber = temp.num; \
  282. }
  283. #define INIT_GMP_RETVAL(gmpnumber) \
  284. gmp_create_ex(return_value, &gmpnumber TSRMLS_CC)
  285. static void gmp_strval(zval *result, mpz_t gmpnum, long base);
  286. static int convert_to_gmp(mpz_t gmpnumber, zval *val, int base TSRMLS_DC);
  287. static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg TSRMLS_DC);
  288. /*
  289. * The gmp_*_op functions provide an implementation for several common types
  290. * of GMP functions. The gmp_zval_(unary|binary)_*_op functions have to be manually
  291. * passed zvals to work on, whereas the gmp_(unary|binary)_*_op macros already
  292. * include parameter parsing.
  293. */
  294. typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr);
  295. typedef int (*gmp_unary_opl_t)(mpz_srcptr);
  296. typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long);
  297. typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr);
  298. typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr);
  299. typedef void (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long);
  300. typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
  301. typedef void (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long);
  302. static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC);
  303. static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero TSRMLS_DC);
  304. static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op TSRMLS_DC);
  305. static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC);
  306. /* Binary operations */
  307. #define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 0)
  308. #define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL, 0)
  309. #define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
  310. #define gmp_binary_ui_op_no_zero(op, uop) \
  311. _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 1)
  312. /* Unary operations */
  313. #define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
  314. #define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
  315. #define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
  316. static inline long gmp_get_long(zval *zv) /* {{{ */
  317. {
  318. if (Z_TYPE_P(zv) == IS_LONG) {
  319. return Z_LVAL_P(zv);
  320. } else {
  321. zval tmp_zv;
  322. MAKE_COPY_ZVAL(&zv, &tmp_zv);
  323. convert_to_long(&tmp_zv);
  324. return Z_LVAL(tmp_zv);
  325. }
  326. }
  327. /* }}} */
  328. static void gmp_free_object_storage(gmp_object *intern TSRMLS_DC) /* {{{ */
  329. {
  330. mpz_clear(intern->num);
  331. zend_object_std_dtor(&intern->std TSRMLS_CC);
  332. efree(intern);
  333. }
  334. /* }}} */
  335. static inline zend_object_value gmp_create_object_ex(zend_class_entry *ce, mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */
  336. {
  337. zend_object_value retval;
  338. gmp_object *intern = emalloc(sizeof(gmp_object));
  339. zend_object_std_init(&intern->std, ce TSRMLS_CC);
  340. object_properties_init(&intern->std, ce);
  341. mpz_init(intern->num);
  342. *gmpnum_target = intern->num;
  343. retval.handle = zend_objects_store_put(
  344. intern, (zend_objects_store_dtor_t) zend_objects_destroy_object,
  345. (zend_objects_free_object_storage_t) gmp_free_object_storage,
  346. NULL TSRMLS_CC
  347. );
  348. retval.handlers = &gmp_object_handlers;
  349. return retval;
  350. }
  351. /* }}} */
  352. static zend_object_value gmp_create_object(zend_class_entry *ce TSRMLS_DC) /* {{{ */
  353. {
  354. mpz_ptr gmpnum_dummy;
  355. return gmp_create_object_ex(ce, &gmpnum_dummy TSRMLS_CC);
  356. }
  357. /* }}} */
  358. static inline void gmp_create_ex(zval *target, mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */
  359. {
  360. Z_TYPE_P(target) = IS_OBJECT;
  361. Z_OBJVAL_P(target) = gmp_create_object_ex(gmp_ce, gmpnum_target TSRMLS_CC);
  362. }
  363. /* }}} */
  364. static zval *gmp_create(mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */
  365. {
  366. zval *obj;
  367. MAKE_STD_ZVAL(obj);
  368. gmp_create_ex(obj, gmpnum_target TSRMLS_CC);
  369. return obj;
  370. }
  371. /* }}} */
  372. static int gmp_cast_object(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */
  373. {
  374. mpz_ptr gmpnum;
  375. switch (type) {
  376. case IS_STRING:
  377. gmpnum = GET_GMP_FROM_ZVAL(readobj);
  378. INIT_PZVAL(writeobj);
  379. gmp_strval(writeobj, gmpnum, 10);
  380. return SUCCESS;
  381. case IS_LONG:
  382. gmpnum = GET_GMP_FROM_ZVAL(readobj);
  383. INIT_PZVAL(writeobj);
  384. ZVAL_LONG(writeobj, mpz_get_si(gmpnum));
  385. return SUCCESS;
  386. case IS_DOUBLE:
  387. gmpnum = GET_GMP_FROM_ZVAL(readobj);
  388. INIT_PZVAL(writeobj);
  389. ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
  390. return SUCCESS;
  391. default:
  392. return FAILURE;
  393. }
  394. }
  395. /* }}} */
  396. static HashTable *gmp_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
  397. {
  398. HashTable *ht, *props = zend_std_get_properties(obj TSRMLS_CC);
  399. mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(obj);
  400. zval *zv;
  401. *is_temp = 1;
  402. ALLOC_HASHTABLE(ht);
  403. ZEND_INIT_SYMTABLE_EX(ht, zend_hash_num_elements(props) + 1, 0);
  404. zend_hash_copy(ht, props, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
  405. MAKE_STD_ZVAL(zv);
  406. gmp_strval(zv, gmpnum, 10);
  407. zend_hash_update(ht, "num", sizeof("num"), &zv, sizeof(zval *), NULL);
  408. return ht;
  409. }
  410. /* }}} */
  411. static zend_object_value gmp_clone_obj(zval *obj TSRMLS_DC) /* {{{ */
  412. {
  413. gmp_object *old_object = zend_object_store_get_object(obj TSRMLS_CC);
  414. zend_object_value new_object_val = gmp_create_object(Z_OBJCE_P(obj) TSRMLS_CC);
  415. gmp_object *new_object = zend_object_store_get_object_by_handle(
  416. new_object_val.handle TSRMLS_CC
  417. );
  418. zend_objects_clone_members(
  419. &new_object->std, new_object_val,
  420. &old_object->std, Z_OBJ_HANDLE_P(obj) TSRMLS_CC
  421. );
  422. mpz_set(new_object->num, old_object->num);
  423. return new_object_val;
  424. }
  425. /* }}} */
  426. static void shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2 TSRMLS_DC) {
  427. zval op2_copy;
  428. if (Z_TYPE_P(op2) != IS_LONG) {
  429. op2_copy = *op2;
  430. zval_copy_ctor(&op2_copy);
  431. convert_to_long(&op2_copy);
  432. op2 = &op2_copy;
  433. }
  434. if (Z_LVAL_P(op2) < 0) {
  435. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shift cannot be negative");
  436. RETVAL_FALSE;
  437. } else {
  438. mpz_ptr gmpnum_op, gmpnum_result;
  439. gmp_temp_t temp;
  440. FETCH_GMP_ZVAL(gmpnum_op, op1, temp);
  441. INIT_GMP_RETVAL(gmpnum_result);
  442. op(gmpnum_result, gmpnum_op, (unsigned long) Z_LVAL_P(op2));
  443. FREE_GMP_TEMP(temp);
  444. }
  445. }
  446. #define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \
  447. gmp_zval_binary_ui_op( \
  448. result, op1, op2, op, (gmp_binary_ui_op_t) uop, \
  449. check_b_zero TSRMLS_CC \
  450. ); \
  451. return SUCCESS;
  452. #define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0)
  453. #define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0)
  454. #define DO_UNARY_OP(op) \
  455. gmp_zval_unary_op(result, op1, op TSRMLS_CC); \
  456. return SUCCESS;
  457. static int gmp_do_operation_ex(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
  458. {
  459. switch (opcode) {
  460. case ZEND_ADD:
  461. DO_BINARY_UI_OP(mpz_add);
  462. case ZEND_SUB:
  463. DO_BINARY_UI_OP(mpz_sub);
  464. case ZEND_MUL:
  465. DO_BINARY_UI_OP(mpz_mul);
  466. case ZEND_POW:
  467. shift_operator_helper(mpz_pow_ui, result, op1, op2 TSRMLS_CC);
  468. return SUCCESS;
  469. case ZEND_DIV:
  470. DO_BINARY_UI_OP_EX(mpz_tdiv_q, mpz_tdiv_q_ui, 1);
  471. case ZEND_MOD:
  472. DO_BINARY_UI_OP_EX(mpz_mod, mpz_mod_ui, 1);
  473. case ZEND_SL:
  474. shift_operator_helper(mpz_mul_2exp, result, op1, op2 TSRMLS_CC);
  475. return SUCCESS;
  476. case ZEND_SR:
  477. shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2 TSRMLS_CC);
  478. return SUCCESS;
  479. case ZEND_BW_OR:
  480. DO_BINARY_OP(mpz_ior);
  481. case ZEND_BW_AND:
  482. DO_BINARY_OP(mpz_and);
  483. case ZEND_BW_XOR:
  484. DO_BINARY_OP(mpz_xor);
  485. case ZEND_BW_NOT:
  486. DO_UNARY_OP(mpz_com);
  487. default:
  488. return FAILURE;
  489. }
  490. }
  491. /* }}} */
  492. static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
  493. {
  494. zval op1_copy;
  495. int retval;
  496. if (result == op1) {
  497. ZVAL_COPY_VALUE(&op1_copy, op1);
  498. op1 = &op1_copy;
  499. }
  500. retval = gmp_do_operation_ex(opcode, result, op1, op2 TSRMLS_CC);
  501. if (retval == SUCCESS && op1 == &op1_copy) {
  502. zval_dtor(op1);
  503. }
  504. return retval;
  505. }
  506. /* }}} */
  507. static int gmp_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
  508. {
  509. gmp_cmp(result, op1, op2 TSRMLS_CC);
  510. if (Z_TYPE_P(result) == IS_BOOL) {
  511. ZVAL_LONG(result, 1);
  512. }
  513. return SUCCESS;
  514. }
  515. /* }}} */
  516. static int gmp_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) /* {{{ */
  517. {
  518. mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(object);
  519. smart_str buf = {0};
  520. zval zv, *zv_ptr = &zv;
  521. php_serialize_data_t serialize_data = (php_serialize_data_t) data;
  522. PHP_VAR_SERIALIZE_INIT(serialize_data);
  523. INIT_PZVAL(zv_ptr);
  524. gmp_strval(zv_ptr, gmpnum, 10);
  525. php_var_serialize(&buf, &zv_ptr, &serialize_data TSRMLS_CC);
  526. zval_dtor(zv_ptr);
  527. Z_ARRVAL_P(zv_ptr) = zend_std_get_properties(object TSRMLS_CC);
  528. Z_TYPE_P(zv_ptr) = IS_ARRAY;
  529. php_var_serialize(&buf, &zv_ptr, &serialize_data TSRMLS_CC);
  530. PHP_VAR_SERIALIZE_DESTROY(serialize_data);
  531. *buffer = (unsigned char *) buf.c;
  532. *buf_len = buf.len;
  533. return SUCCESS;
  534. }
  535. /* }}} */
  536. static int gmp_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC) /* {{{ */
  537. {
  538. mpz_ptr gmpnum;
  539. const unsigned char *p, *max;
  540. zval *zv_ptr;
  541. int retval = FAILURE;
  542. php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
  543. PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
  544. gmp_create_ex(*object, &gmpnum TSRMLS_CC);
  545. p = buf;
  546. max = buf + buf_len;
  547. ALLOC_INIT_ZVAL(zv_ptr);
  548. if (!php_var_unserialize(&zv_ptr, &p, max, &unserialize_data TSRMLS_CC)
  549. || Z_TYPE_P(zv_ptr) != IS_STRING
  550. || convert_to_gmp(gmpnum, zv_ptr, 10 TSRMLS_CC) == FAILURE
  551. ) {
  552. zend_throw_exception(NULL, "Could not unserialize number", 0 TSRMLS_CC);
  553. goto exit;
  554. }
  555. var_push_dtor_no_addref(&unserialize_data, &zv_ptr);
  556. ALLOC_INIT_ZVAL(zv_ptr);
  557. if (!php_var_unserialize(&zv_ptr, &p, max, &unserialize_data TSRMLS_CC)
  558. || Z_TYPE_P(zv_ptr) != IS_ARRAY
  559. ) {
  560. zend_throw_exception(NULL, "Could not unserialize properties", 0 TSRMLS_CC);
  561. goto exit;
  562. }
  563. if (zend_hash_num_elements(Z_ARRVAL_P(zv_ptr)) != 0) {
  564. zend_hash_copy(
  565. zend_std_get_properties(*object TSRMLS_CC), Z_ARRVAL_P(zv_ptr),
  566. (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)
  567. );
  568. }
  569. retval = SUCCESS;
  570. exit:
  571. var_push_dtor_no_addref(&unserialize_data, &zv_ptr);
  572. PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
  573. return retval;
  574. }
  575. /* }}} */
  576. /* {{{ ZEND_GINIT_FUNCTION
  577. */
  578. static ZEND_GINIT_FUNCTION(gmp)
  579. {
  580. gmp_globals->rand_initialized = 0;
  581. }
  582. /* }}} */
  583. /* {{{ ZEND_MINIT_FUNCTION
  584. */
  585. ZEND_MINIT_FUNCTION(gmp)
  586. {
  587. zend_class_entry tmp_ce;
  588. INIT_CLASS_ENTRY(tmp_ce, "GMP", NULL);
  589. gmp_ce = zend_register_internal_class(&tmp_ce TSRMLS_CC);
  590. gmp_ce->create_object = gmp_create_object;
  591. gmp_ce->serialize = gmp_serialize;
  592. gmp_ce->unserialize = gmp_unserialize;
  593. memcpy(&gmp_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
  594. gmp_object_handlers.cast_object = gmp_cast_object;
  595. gmp_object_handlers.get_debug_info = gmp_get_debug_info;
  596. gmp_object_handlers.clone_obj = gmp_clone_obj;
  597. gmp_object_handlers.do_operation = gmp_do_operation;
  598. gmp_object_handlers.compare = gmp_compare;
  599. REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT);
  600. REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT);
  601. REGISTER_LONG_CONSTANT("GMP_ROUND_MINUSINF", GMP_ROUND_MINUSINF, CONST_CS | CONST_PERSISTENT);
  602. #ifdef mpir_version
  603. REGISTER_STRING_CONSTANT("GMP_MPIR_VERSION", (char *)mpir_version, CONST_CS | CONST_PERSISTENT);
  604. #endif
  605. REGISTER_STRING_CONSTANT("GMP_VERSION", (char *)gmp_version, CONST_CS | CONST_PERSISTENT);
  606. REGISTER_LONG_CONSTANT("GMP_MSW_FIRST", GMP_MSW_FIRST, CONST_CS | CONST_PERSISTENT);
  607. REGISTER_LONG_CONSTANT("GMP_LSW_FIRST", GMP_LSW_FIRST, CONST_CS | CONST_PERSISTENT);
  608. REGISTER_LONG_CONSTANT("GMP_LITTLE_ENDIAN", GMP_LITTLE_ENDIAN, CONST_CS | CONST_PERSISTENT);
  609. REGISTER_LONG_CONSTANT("GMP_BIG_ENDIAN", GMP_BIG_ENDIAN, CONST_CS | CONST_PERSISTENT);
  610. REGISTER_LONG_CONSTANT("GMP_NATIVE_ENDIAN", GMP_NATIVE_ENDIAN, CONST_CS | CONST_PERSISTENT);
  611. return SUCCESS;
  612. }
  613. /* }}} */
  614. /* {{{ ZEND_RSHUTDOWN_FUNCTION
  615. */
  616. ZEND_MODULE_DEACTIVATE_D(gmp)
  617. {
  618. if (GMPG(rand_initialized)) {
  619. gmp_randclear(GMPG(rand_state));
  620. GMPG(rand_initialized) = 0;
  621. }
  622. return SUCCESS;
  623. }
  624. /* }}} */
  625. /* {{{ ZEND_MINFO_FUNCTION
  626. */
  627. ZEND_MODULE_INFO_D(gmp)
  628. {
  629. php_info_print_table_start();
  630. php_info_print_table_row(2, "gmp support", "enabled");
  631. #ifdef mpir_version
  632. php_info_print_table_row(2, "MPIR version", mpir_version);
  633. #else
  634. php_info_print_table_row(2, "GMP version", gmp_version);
  635. #endif
  636. php_info_print_table_end();
  637. }
  638. /* }}} */
  639. /* {{{ convert_to_gmp
  640. * Convert zval to be gmp number */
  641. static int convert_to_gmp(mpz_t gmpnumber, zval *val, int base TSRMLS_DC)
  642. {
  643. switch (Z_TYPE_P(val)) {
  644. case IS_LONG:
  645. case IS_BOOL: {
  646. mpz_set_si(gmpnumber, gmp_get_long(val));
  647. return SUCCESS;
  648. }
  649. case IS_STRING: {
  650. char *numstr = Z_STRVAL_P(val);
  651. int skip_lead = 0;
  652. int ret;
  653. if (Z_STRLEN_P(val) > 2 && numstr[0] == '0') {
  654. if ((base == 0 || base == 16) && (numstr[1] == 'x' || numstr[1] == 'X')) {
  655. base = 16;
  656. skip_lead = 1;
  657. } else if ((base == 0 || base == 2) && (numstr[1] == 'b' || numstr[1] == 'B')) {
  658. base = 2;
  659. skip_lead = 1;
  660. }
  661. }
  662. ret = mpz_set_str(gmpnumber, (skip_lead ? &numstr[2] : numstr), base);
  663. if (-1 == ret) {
  664. php_error_docref(NULL TSRMLS_CC, E_WARNING,
  665. "Unable to convert variable to GMP - string is not an integer");
  666. return FAILURE;
  667. }
  668. return SUCCESS;
  669. }
  670. default:
  671. php_error_docref(NULL TSRMLS_CC, E_WARNING,
  672. "Unable to convert variable to GMP - wrong type");
  673. return FAILURE;
  674. }
  675. }
  676. /* }}} */
  677. static void gmp_strval(zval *result, mpz_t gmpnum, long base) /* {{{ */
  678. {
  679. int num_len;
  680. char *out_string;
  681. num_len = mpz_sizeinbase(gmpnum, abs(base));
  682. if (mpz_sgn(gmpnum) < 0) {
  683. num_len++;
  684. }
  685. out_string = emalloc(num_len + 1);
  686. mpz_get_str(out_string, base, gmpnum);
  687. /*
  688. * From GMP documentation for mpz_sizeinbase():
  689. * The returned value will be exact or 1 too big. If base is a power of
  690. * 2, the returned value will always be exact.
  691. *
  692. * So let's check to see if we already have a \0 byte...
  693. */
  694. if (out_string[num_len - 1] == '\0') {
  695. num_len--;
  696. } else {
  697. out_string[num_len] = '\0';
  698. }
  699. ZVAL_STRINGL(result, out_string, num_len, 0);
  700. }
  701. /* }}} */
  702. static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg TSRMLS_DC) /* {{{ */
  703. {
  704. mpz_ptr gmpnum_a, gmpnum_b;
  705. gmp_temp_t temp_a, temp_b;
  706. zend_bool use_si = 0;
  707. long res;
  708. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  709. if (Z_TYPE_P(b_arg) == IS_LONG) {
  710. use_si = 1;
  711. temp_b.is_used = 0;
  712. } else {
  713. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
  714. }
  715. if (use_si) {
  716. res = mpz_cmp_si(gmpnum_a, Z_LVAL_P(b_arg));
  717. } else {
  718. res = mpz_cmp(gmpnum_a, gmpnum_b);
  719. }
  720. FREE_GMP_TEMP(temp_a);
  721. FREE_GMP_TEMP(temp_b);
  722. RETURN_LONG(res);
  723. }
  724. /* }}} */
  725. /* {{{ gmp_zval_binary_ui_op
  726. Execute GMP binary operation.
  727. */
  728. static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC)
  729. {
  730. mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
  731. int use_ui = 0;
  732. gmp_temp_t temp_a, temp_b;
  733. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  734. if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
  735. use_ui = 1;
  736. temp_b.is_used = 0;
  737. } else {
  738. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
  739. }
  740. if (check_b_zero) {
  741. int b_is_zero = 0;
  742. if (use_ui) {
  743. b_is_zero = (Z_LVAL_P(b_arg) == 0);
  744. } else {
  745. b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
  746. }
  747. if (b_is_zero) {
  748. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed");
  749. FREE_GMP_TEMP(temp_a);
  750. FREE_GMP_TEMP(temp_b);
  751. RETURN_FALSE;
  752. }
  753. }
  754. INIT_GMP_RETVAL(gmpnum_result);
  755. if (use_ui) {
  756. gmp_ui_op(gmpnum_result, gmpnum_a, (unsigned long) Z_LVAL_P(b_arg));
  757. } else {
  758. gmp_op(gmpnum_result, gmpnum_a, gmpnum_b);
  759. }
  760. FREE_GMP_TEMP(temp_a);
  761. FREE_GMP_TEMP(temp_b);
  762. }
  763. /* }}} */
  764. /* {{{ gmp_zval_binary_ui_op2
  765. Execute GMP binary operation which returns 2 values.
  766. */
  767. static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero TSRMLS_DC)
  768. {
  769. mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result1, gmpnum_result2;
  770. int use_ui = 0;
  771. gmp_temp_t temp_a, temp_b;
  772. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  773. if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
  774. /* use _ui function */
  775. use_ui = 1;
  776. temp_b.is_used = 0;
  777. } else {
  778. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
  779. }
  780. if (check_b_zero) {
  781. int b_is_zero = 0;
  782. if (use_ui) {
  783. b_is_zero = (Z_LVAL_P(b_arg) == 0);
  784. } else {
  785. b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
  786. }
  787. if (b_is_zero) {
  788. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed");
  789. FREE_GMP_TEMP(temp_a);
  790. FREE_GMP_TEMP(temp_b);
  791. RETURN_FALSE;
  792. }
  793. }
  794. array_init(return_value);
  795. add_index_zval(return_value, 0, gmp_create(&gmpnum_result1 TSRMLS_CC));
  796. add_index_zval(return_value, 1, gmp_create(&gmpnum_result2 TSRMLS_CC));
  797. if (use_ui) {
  798. gmp_ui_op(gmpnum_result1, gmpnum_result2, gmpnum_a, (unsigned long) Z_LVAL_P(b_arg));
  799. } else {
  800. gmp_op(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b);
  801. }
  802. FREE_GMP_TEMP(temp_a);
  803. FREE_GMP_TEMP(temp_b);
  804. }
  805. /* }}} */
  806. /* {{{ _gmp_binary_ui_op
  807. */
  808. static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero)
  809. {
  810. zval *a_arg, *b_arg;
  811. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){
  812. return;
  813. }
  814. gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero TSRMLS_CC);
  815. }
  816. /* }}} */
  817. /* Unary operations */
  818. /* {{{ gmp_zval_unary_op
  819. */
  820. static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op TSRMLS_DC)
  821. {
  822. mpz_ptr gmpnum_a, gmpnum_result;
  823. gmp_temp_t temp_a;
  824. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  825. INIT_GMP_RETVAL(gmpnum_result);
  826. gmp_op(gmpnum_result, gmpnum_a);
  827. FREE_GMP_TEMP(temp_a);
  828. }
  829. /* }}} */
  830. /* {{{ gmp_zval_unary_ui_op
  831. */
  832. static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC)
  833. {
  834. mpz_ptr gmpnum_result;
  835. INIT_GMP_RETVAL(gmpnum_result);
  836. gmp_op(gmpnum_result, gmp_get_long(a_arg));
  837. }
  838. /* }}} */
  839. /* {{{ _gmp_unary_ui_op
  840. Execute GMP unary operation.
  841. */
  842. static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op)
  843. {
  844. zval *a_arg;
  845. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
  846. return;
  847. }
  848. gmp_zval_unary_ui_op(return_value, a_arg, gmp_op TSRMLS_CC);
  849. }
  850. /* }}} */
  851. /* {{{ _gmp_unary_op
  852. */
  853. static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op)
  854. {
  855. zval *a_arg;
  856. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
  857. return;
  858. }
  859. gmp_zval_unary_op(return_value, a_arg, gmp_op TSRMLS_CC);
  860. }
  861. /* }}} */
  862. /* {{{ _gmp_unary_opl
  863. */
  864. static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op)
  865. {
  866. zval *a_arg;
  867. mpz_ptr gmpnum_a;
  868. gmp_temp_t temp_a;
  869. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
  870. return;
  871. }
  872. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  873. RETVAL_LONG(gmp_op(gmpnum_a));
  874. FREE_GMP_TEMP(temp_a);
  875. }
  876. /* }}} */
  877. /* {{{ _gmp_binary_opl
  878. */
  879. static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op)
  880. {
  881. zval *a_arg, *b_arg;
  882. mpz_ptr gmpnum_a, gmpnum_b;
  883. gmp_temp_t temp_a, temp_b;
  884. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){
  885. return;
  886. }
  887. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  888. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
  889. RETVAL_LONG(gmp_op(gmpnum_a, gmpnum_b));
  890. FREE_GMP_TEMP(temp_a);
  891. FREE_GMP_TEMP(temp_b);
  892. }
  893. /* }}} */
  894. /* {{{ proto GMP gmp_init(mixed number [, int base])
  895. Initializes GMP number */
  896. ZEND_FUNCTION(gmp_init)
  897. {
  898. zval *number_arg;
  899. mpz_ptr gmpnumber;
  900. long base = 0;
  901. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &number_arg, &base) == FAILURE) {
  902. return;
  903. }
  904. if (base && (base < 2 || base > MAX_BASE)) {
  905. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE);
  906. RETURN_FALSE;
  907. }
  908. INIT_GMP_RETVAL(gmpnumber);
  909. if (convert_to_gmp(gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) {
  910. zval_dtor(return_value);
  911. RETURN_FALSE;
  912. }
  913. }
  914. /* }}} */
  915. int gmp_import_export_validate(long size, long options, int *order, int *endian TSRMLS_DC)
  916. {
  917. if (size < 1) {
  918. php_error_docref(NULL TSRMLS_CC, E_WARNING,
  919. "Word size must be positive, %ld given", size);
  920. return FAILURE;
  921. }
  922. switch (options & (GMP_LSW_FIRST | GMP_MSW_FIRST)) {
  923. case GMP_LSW_FIRST:
  924. *order = -1;
  925. break;
  926. case GMP_MSW_FIRST:
  927. case 0: /* default */
  928. *order = 1;
  929. break;
  930. default:
  931. php_error_docref(NULL TSRMLS_CC, E_WARNING,
  932. "Invalid options: Conflicting word orders");
  933. return FAILURE;
  934. }
  935. switch (options & (GMP_LITTLE_ENDIAN | GMP_BIG_ENDIAN | GMP_NATIVE_ENDIAN)) {
  936. case GMP_LITTLE_ENDIAN:
  937. *endian = -1;
  938. break;
  939. case GMP_BIG_ENDIAN:
  940. *endian = 1;
  941. break;
  942. case GMP_NATIVE_ENDIAN:
  943. case 0: /* default */
  944. *endian = 0;
  945. break;
  946. default:
  947. php_error_docref(NULL TSRMLS_CC, E_WARNING,
  948. "Invalid options: Conflicting word endianness");
  949. return FAILURE;
  950. }
  951. return SUCCESS;
  952. }
  953. /* {{{ proto GMP gmp_import(string data [, int word_size = 1, int options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN])
  954. Imports a GMP number from a binary string */
  955. ZEND_FUNCTION(gmp_import)
  956. {
  957. char *data;
  958. int data_len;
  959. long size = 1;
  960. long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN;
  961. int order, endian;
  962. mpz_ptr gmpnumber;
  963. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &data, &data_len, &size, &options) == FAILURE) {
  964. return;
  965. }
  966. if (gmp_import_export_validate(size, options, &order, &endian TSRMLS_CC) == FAILURE) {
  967. RETURN_FALSE;
  968. }
  969. if ((data_len % size) != 0) {
  970. php_error_docref(NULL TSRMLS_CC, E_WARNING,
  971. "Input length must be a multiple of word size");
  972. RETURN_FALSE;
  973. }
  974. INIT_GMP_RETVAL(gmpnumber);
  975. mpz_import(gmpnumber, data_len / size, order, size, endian, 0, data);
  976. }
  977. /* }}} */
  978. /* {{{ proto string gmp_export(GMP gmpnumber [, int word_size = 1, int options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN])
  979. Exports a GMP number to a binary string */
  980. ZEND_FUNCTION(gmp_export)
  981. {
  982. zval *gmpnumber_arg;
  983. long size = 1;
  984. long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN;
  985. int order, endian;
  986. mpz_ptr gmpnumber;
  987. gmp_temp_t temp_a;
  988. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &gmpnumber_arg, &size, &options) == FAILURE) {
  989. return;
  990. }
  991. if (gmp_import_export_validate(size, options, &order, &endian TSRMLS_CC) == FAILURE) {
  992. RETURN_FALSE;
  993. }
  994. FETCH_GMP_ZVAL(gmpnumber, gmpnumber_arg, temp_a);
  995. if (mpz_sgn(gmpnumber) == 0) {
  996. RETURN_EMPTY_STRING();
  997. } else {
  998. size_t bits_per_word = size * 8;
  999. size_t count = (mpz_sizeinbase(gmpnumber, 2) + bits_per_word - 1) / bits_per_word;
  1000. size_t out_len = count * size;
  1001. char *out_string = emalloc(out_len + 1);
  1002. mpz_export(out_string, NULL, order, size, endian, 0, gmpnumber);
  1003. out_string[out_len] = '\0';
  1004. RETURN_STRINGL(out_string, out_len, 0);
  1005. }
  1006. FREE_GMP_TEMP(temp_a);
  1007. }
  1008. /* }}} */
  1009. /* {{{ proto int gmp_intval(mixed gmpnumber)
  1010. Gets signed long value of GMP number */
  1011. ZEND_FUNCTION(gmp_intval)
  1012. {
  1013. zval *gmpnumber_arg;
  1014. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &gmpnumber_arg) == FAILURE){
  1015. return;
  1016. }
  1017. if (IS_GMP(gmpnumber_arg)) {
  1018. RETVAL_LONG(mpz_get_si(GET_GMP_FROM_ZVAL(gmpnumber_arg)));
  1019. } else {
  1020. RETVAL_LONG(gmp_get_long(gmpnumber_arg));
  1021. }
  1022. }
  1023. /* }}} */
  1024. /* {{{ proto string gmp_strval(mixed gmpnumber [, int base])
  1025. Gets string representation of GMP number */
  1026. ZEND_FUNCTION(gmp_strval)
  1027. {
  1028. zval *gmpnumber_arg;
  1029. long base = 10;
  1030. mpz_ptr gmpnum;
  1031. gmp_temp_t temp_a;
  1032. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &gmpnumber_arg, &base) == FAILURE) {
  1033. return;
  1034. }
  1035. #if MAX_BASE == 62
  1036. /* Although the maximum base in general in GMP >= 4.2 is 62, mpz_get_str()
  1037. * is explicitly limited to -36 when dealing with negative bases. */
  1038. if ((base < 2 && base > -2) || base > MAX_BASE || base < -36) {
  1039. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d or -2 and -36)", base, MAX_BASE);
  1040. #else
  1041. if (base < 2 || base > MAX_BASE) {
  1042. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE);
  1043. #endif
  1044. RETURN_FALSE;
  1045. }
  1046. FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a);
  1047. gmp_strval(return_value, gmpnum, base);
  1048. FREE_GMP_TEMP(temp_a);
  1049. }
  1050. /* }}} */
  1051. /* {{{ proto GMP gmp_add(mixed a, mixed b)
  1052. Add a and b */
  1053. ZEND_FUNCTION(gmp_add)
  1054. {
  1055. gmp_binary_ui_op(mpz_add, mpz_add_ui);
  1056. }
  1057. /* }}} */
  1058. /* {{{ proto GMP gmp_sub(mixed a, mixed b)
  1059. Subtract b from a */
  1060. ZEND_FUNCTION(gmp_sub)
  1061. {
  1062. gmp_binary_ui_op(mpz_sub, mpz_sub_ui);
  1063. }
  1064. /* }}} */
  1065. /* {{{ proto GMP gmp_mul(mixed a, mixed b)
  1066. Multiply a and b */
  1067. ZEND_FUNCTION(gmp_mul)
  1068. {
  1069. gmp_binary_ui_op(mpz_mul, mpz_mul_ui);
  1070. }
  1071. /* }}} */
  1072. /* {{{ proto array gmp_div_qr(mixed a, mixed b [, int round])
  1073. Divide a by b, returns quotient and reminder */
  1074. ZEND_FUNCTION(gmp_div_qr)
  1075. {
  1076. zval *a_arg, *b_arg;
  1077. long round = GMP_ROUND_ZERO;
  1078. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
  1079. return;
  1080. }
  1081. switch (round) {
  1082. case GMP_ROUND_ZERO:
  1083. gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t) mpz_tdiv_qr_ui, 1 TSRMLS_CC);
  1084. break;
  1085. case GMP_ROUND_PLUSINF:
  1086. gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t) mpz_cdiv_qr_ui, 1 TSRMLS_CC);
  1087. break;
  1088. case GMP_ROUND_MINUSINF:
  1089. gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t) mpz_fdiv_qr_ui, 1 TSRMLS_CC);
  1090. break;
  1091. default:
  1092. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode");
  1093. RETURN_FALSE;
  1094. }
  1095. }
  1096. /* }}} */
  1097. /* {{{ proto GMP gmp_div_r(mixed a, mixed b [, int round])
  1098. Divide a by b, returns reminder only */
  1099. ZEND_FUNCTION(gmp_div_r)
  1100. {
  1101. zval *a_arg, *b_arg;
  1102. long round = GMP_ROUND_ZERO;
  1103. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
  1104. return;
  1105. }
  1106. switch (round) {
  1107. case GMP_ROUND_ZERO:
  1108. gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t) mpz_tdiv_r_ui, 1 TSRMLS_CC);
  1109. break;
  1110. case GMP_ROUND_PLUSINF:
  1111. gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t) mpz_cdiv_r_ui, 1 TSRMLS_CC);
  1112. break;
  1113. case GMP_ROUND_MINUSINF:
  1114. gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t) mpz_fdiv_r_ui, 1 TSRMLS_CC);
  1115. break;
  1116. default:
  1117. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode");
  1118. RETURN_FALSE;
  1119. }
  1120. }
  1121. /* }}} */
  1122. /* {{{ proto GMP gmp_div_q(mixed a, mixed b [, int round])
  1123. Divide a by b, returns quotient only */
  1124. ZEND_FUNCTION(gmp_div_q)
  1125. {
  1126. zval *a_arg, *b_arg;
  1127. long round = GMP_ROUND_ZERO;
  1128. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
  1129. return;
  1130. }
  1131. switch (round) {
  1132. case GMP_ROUND_ZERO:
  1133. gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t) mpz_tdiv_q_ui, 1 TSRMLS_CC);
  1134. break;
  1135. case GMP_ROUND_PLUSINF:
  1136. gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t) mpz_cdiv_q_ui, 1 TSRMLS_CC);
  1137. break;
  1138. case GMP_ROUND_MINUSINF:
  1139. gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t) mpz_fdiv_q_ui, 1 TSRMLS_CC);
  1140. break;
  1141. default:
  1142. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode");
  1143. RETURN_FALSE;
  1144. }
  1145. }
  1146. /* }}} */
  1147. /* {{{ proto GMP gmp_mod(mixed a, mixed b)
  1148. Computes a modulo b */
  1149. ZEND_FUNCTION(gmp_mod)
  1150. {
  1151. gmp_binary_ui_op_no_zero(mpz_mod, (gmp_binary_ui_op_t) mpz_mod_ui);
  1152. }
  1153. /* }}} */
  1154. /* {{{ proto GMP gmp_divexact(mixed a, mixed b)
  1155. Divide a by b using exact division algorithm */
  1156. ZEND_FUNCTION(gmp_divexact)
  1157. {
  1158. gmp_binary_ui_op_no_zero(mpz_divexact, NULL);
  1159. }
  1160. /* }}} */
  1161. /* {{{ proto GMP gmp_neg(mixed a)
  1162. Negates a number */
  1163. ZEND_FUNCTION(gmp_neg)
  1164. {
  1165. gmp_unary_op(mpz_neg);
  1166. }
  1167. /* }}} */
  1168. /* {{{ proto GMP gmp_abs(mixed a)
  1169. Calculates absolute value */
  1170. ZEND_FUNCTION(gmp_abs)
  1171. {
  1172. gmp_unary_op(mpz_abs);
  1173. }
  1174. /* }}} */
  1175. /* {{{ proto GMP gmp_fact(int a)
  1176. Calculates factorial function */
  1177. ZEND_FUNCTION(gmp_fact)
  1178. {
  1179. zval *a_arg;
  1180. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
  1181. return;
  1182. }
  1183. if (IS_GMP(a_arg)) {
  1184. mpz_ptr gmpnum_tmp = GET_GMP_FROM_ZVAL(a_arg);
  1185. if (mpz_sgn(gmpnum_tmp) < 0) {
  1186. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
  1187. RETURN_FALSE;
  1188. }
  1189. } else {
  1190. if (gmp_get_long(a_arg) < 0) {
  1191. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
  1192. RETURN_FALSE;
  1193. }
  1194. }
  1195. gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui TSRMLS_CC);
  1196. }
  1197. /* }}} */
  1198. /* {{{ proto GMP gmp_pow(mixed base, int exp)
  1199. Raise base to power exp */
  1200. ZEND_FUNCTION(gmp_pow)
  1201. {
  1202. zval *base_arg;
  1203. mpz_ptr gmpnum_result, gmpnum_base;
  1204. gmp_temp_t temp_base;
  1205. long exp;
  1206. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &base_arg, &exp) == FAILURE) {
  1207. return;
  1208. }
  1209. if (exp < 0) {
  1210. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative exponent not supported");
  1211. RETURN_FALSE;
  1212. }
  1213. if (Z_TYPE_P(base_arg) == IS_LONG && Z_LVAL_P(base_arg) >= 0) {
  1214. INIT_GMP_RETVAL(gmpnum_result);
  1215. mpz_ui_pow_ui(gmpnum_result, Z_LVAL_P(base_arg), exp);
  1216. } else {
  1217. FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
  1218. INIT_GMP_RETVAL(gmpnum_result);
  1219. mpz_pow_ui(gmpnum_result, gmpnum_base, exp);
  1220. FREE_GMP_TEMP(temp_base);
  1221. }
  1222. }
  1223. /* }}} */
  1224. /* {{{ proto GMP gmp_powm(mixed base, mixed exp, mixed mod)
  1225. Raise base to power exp and take result modulo mod */
  1226. ZEND_FUNCTION(gmp_powm)
  1227. {
  1228. zval *base_arg, *exp_arg, *mod_arg;
  1229. mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result;
  1230. int use_ui = 0;
  1231. gmp_temp_t temp_base, temp_exp, temp_mod;
  1232. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zzz", &base_arg, &exp_arg, &mod_arg) == FAILURE){
  1233. return;
  1234. }
  1235. FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
  1236. if (Z_TYPE_P(exp_arg) == IS_LONG && Z_LVAL_P(exp_arg) >= 0) {
  1237. use_ui = 1;
  1238. temp_exp.is_used = 0;
  1239. } else {
  1240. FETCH_GMP_ZVAL_DEP(gmpnum_exp, exp_arg, temp_exp, temp_base);
  1241. if (mpz_sgn(gmpnum_exp) < 0) {
  1242. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second parameter cannot be less than 0");
  1243. FREE_GMP_TEMP(temp_base);
  1244. FREE_GMP_TEMP(temp_exp);
  1245. RETURN_FALSE;
  1246. }
  1247. }
  1248. FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base);
  1249. if (!mpz_cmp_ui(gmpnum_mod, 0)) {
  1250. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modulus may not be zero");
  1251. FREE_GMP_TEMP(temp_base);
  1252. FREE_GMP_TEMP(temp_exp);
  1253. FREE_GMP_TEMP(temp_mod);
  1254. RETURN_FALSE;
  1255. }
  1256. INIT_GMP_RETVAL(gmpnum_result);
  1257. if (use_ui) {
  1258. mpz_powm_ui(gmpnum_result, gmpnum_base, (unsigned long) Z_LVAL_P(exp_arg), gmpnum_mod);
  1259. } else {
  1260. mpz_powm(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod);
  1261. FREE_GMP_TEMP(temp_exp);
  1262. }
  1263. FREE_GMP_TEMP(temp_base);
  1264. FREE_GMP_TEMP(temp_mod);
  1265. }
  1266. /* }}} */
  1267. /* {{{ proto GMP gmp_sqrt(mixed a)
  1268. Takes integer part of square root of a */
  1269. ZEND_FUNCTION(gmp_sqrt)
  1270. {
  1271. zval *a_arg;
  1272. mpz_ptr gmpnum_a, gmpnum_result;
  1273. gmp_temp_t temp_a;
  1274. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
  1275. return;
  1276. }
  1277. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1278. if (mpz_sgn(gmpnum_a) < 0) {
  1279. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
  1280. FREE_GMP_TEMP(temp_a);
  1281. RETURN_FALSE;
  1282. }
  1283. INIT_GMP_RETVAL(gmpnum_result);
  1284. mpz_sqrt(gmpnum_result, gmpnum_a);
  1285. FREE_GMP_TEMP(temp_a);
  1286. }
  1287. /* }}} */
  1288. /* {{{ proto array gmp_sqrtrem(mixed a)
  1289. Square root with remainder */
  1290. ZEND_FUNCTION(gmp_sqrtrem)
  1291. {
  1292. zval *a_arg;
  1293. mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
  1294. gmp_temp_t temp_a;
  1295. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
  1296. return;
  1297. }
  1298. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1299. if (mpz_sgn(gmpnum_a) < 0) {
  1300. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
  1301. FREE_GMP_TEMP(temp_a);
  1302. RETURN_FALSE;
  1303. }
  1304. array_init(return_value);
  1305. add_index_zval(return_value, 0, gmp_create(&gmpnum_result1 TSRMLS_CC));
  1306. add_index_zval(return_value, 1, gmp_create(&gmpnum_result2 TSRMLS_CC));
  1307. mpz_sqrtrem(gmpnum_result1, gmpnum_result2, gmpnum_a);
  1308. FREE_GMP_TEMP(temp_a);
  1309. }
  1310. /* }}} */
  1311. /* {{{ proto GMP gmp_root(mixed a, int nth)
  1312. Takes integer part of nth root */
  1313. ZEND_FUNCTION(gmp_root)
  1314. {
  1315. zval *a_arg;
  1316. long nth;
  1317. mpz_ptr gmpnum_a, gmpnum_result;
  1318. gmp_temp_t temp_a;
  1319. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &nth) == FAILURE) {
  1320. return;
  1321. }
  1322. if (nth <= 0) {
  1323. php_error_docref(NULL TSRMLS_CC, E_WARNING, "The root must be positive");
  1324. RETURN_FALSE;
  1325. }
  1326. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1327. if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
  1328. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't take even root of negative number");
  1329. FREE_GMP_TEMP(temp_a);
  1330. RETURN_FALSE;
  1331. }
  1332. INIT_GMP_RETVAL(gmpnum_result);
  1333. mpz_root(gmpnum_result, gmpnum_a, (unsigned long) nth);
  1334. FREE_GMP_TEMP(temp_a);
  1335. }
  1336. /* }}} */
  1337. /* {{{ proto GMP gmp_rootrem(mixed a, int nth)
  1338. Calculates integer part of nth root and remainder */
  1339. ZEND_FUNCTION(gmp_rootrem)
  1340. {
  1341. zval *a_arg;
  1342. long nth;
  1343. mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
  1344. gmp_temp_t temp_a;
  1345. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &nth) == FAILURE) {
  1346. return;
  1347. }
  1348. if (nth <= 0) {
  1349. php_error_docref(NULL TSRMLS_CC, E_WARNING, "The root must be positive");
  1350. RETURN_FALSE;
  1351. }
  1352. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1353. if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
  1354. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't take even root of negative number");
  1355. FREE_GMP_TEMP(temp_a);
  1356. RETURN_FALSE;
  1357. }
  1358. array_init(return_value);
  1359. add_index_zval(return_value, 0, gmp_create(&gmpnum_result1 TSRMLS_CC));
  1360. add_index_zval(return_value, 1, gmp_create(&gmpnum_result2 TSRMLS_CC));
  1361. #if GMP_51_OR_NEWER
  1362. /* mpz_rootrem() is supported since GMP 4.2, but buggy wrt odd roots
  1363. * of negative numbers */
  1364. mpz_rootrem(gmpnum_result1, gmpnum_result2, gmpnum_a, (unsigned long) nth);
  1365. #else
  1366. mpz_root(gmpnum_result1, gmpnum_a, (unsigned long) nth);
  1367. mpz_pow_ui(gmpnum_result2, gmpnum_result1, (unsigned long) nth);
  1368. mpz_sub(gmpnum_result2, gmpnum_a, gmpnum_result2);
  1369. #endif
  1370. FREE_GMP_TEMP(temp_a);
  1371. }
  1372. /* }}} */
  1373. /* {{{ proto bool gmp_perfect_square(mixed a)
  1374. Checks if a is an exact square */
  1375. ZEND_FUNCTION(gmp_perfect_square)
  1376. {
  1377. zval *a_arg;
  1378. mpz_ptr gmpnum_a;
  1379. gmp_temp_t temp_a;
  1380. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
  1381. return;
  1382. }
  1383. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1384. RETVAL_BOOL((mpz_perfect_square_p(gmpnum_a) != 0));
  1385. FREE_GMP_TEMP(temp_a);
  1386. }
  1387. /* }}} */
  1388. /* {{{ proto int gmp_prob_prime(mixed a[, int reps])
  1389. Checks if a is "probably prime" */
  1390. ZEND_FUNCTION(gmp_prob_prime)
  1391. {
  1392. zval *gmpnumber_arg;
  1393. mpz_ptr gmpnum_a;
  1394. long reps = 10;
  1395. gmp_temp_t temp_a;
  1396. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &gmpnumber_arg, &reps) == FAILURE) {
  1397. return;
  1398. }
  1399. FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a);
  1400. RETVAL_LONG(mpz_probab_prime_p(gmpnum_a, reps));
  1401. FREE_GMP_TEMP(temp_a);
  1402. }
  1403. /* }}} */
  1404. /* {{{ proto GMP gmp_gcd(mixed a, mixed b)
  1405. Computes greatest common denominator (gcd) of a and b */
  1406. ZEND_FUNCTION(gmp_gcd)
  1407. {
  1408. gmp_binary_ui_op(mpz_gcd, (gmp_binary_ui_op_t) mpz_gcd_ui);
  1409. }
  1410. /* }}} */
  1411. /* {{{ proto array gmp_gcdext(mixed a, mixed b)
  1412. Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */
  1413. ZEND_FUNCTION(gmp_gcdext)
  1414. {
  1415. zval *a_arg, *b_arg;
  1416. mpz_ptr gmpnum_a, gmpnum_b, gmpnum_t, gmpnum_s, gmpnum_g;
  1417. gmp_temp_t temp_a, temp_b;
  1418. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){
  1419. return;
  1420. }
  1421. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1422. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
  1423. array_init(return_value);
  1424. add_assoc_zval(return_value, "g", gmp_create(&gmpnum_g TSRMLS_CC));
  1425. add_assoc_zval(return_value, "s", gmp_create(&gmpnum_s TSRMLS_CC));
  1426. add_assoc_zval(return_value, "t", gmp_create(&gmpnum_t TSRMLS_CC));
  1427. mpz_gcdext(gmpnum_g, gmpnum_s, gmpnum_t, gmpnum_a, gmpnum_b);
  1428. FREE_GMP_TEMP(temp_a);
  1429. FREE_GMP_TEMP(temp_b);
  1430. }
  1431. /* }}} */
  1432. /* {{{ proto GMP gmp_invert(mixed a, mixed b)
  1433. Computes the inverse of a modulo b */
  1434. ZEND_FUNCTION(gmp_invert)
  1435. {
  1436. zval *a_arg, *b_arg;
  1437. mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
  1438. gmp_temp_t temp_a, temp_b;
  1439. int res;
  1440. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){
  1441. return;
  1442. }
  1443. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1444. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
  1445. INIT_GMP_RETVAL(gmpnum_result);
  1446. res = mpz_invert(gmpnum_result, gmpnum_a, gmpnum_b);
  1447. FREE_GMP_TEMP(temp_a);
  1448. FREE_GMP_TEMP(temp_b);
  1449. if (!res) {
  1450. zval_dtor(return_value);
  1451. RETURN_FALSE;
  1452. }
  1453. }
  1454. /* }}} */
  1455. /* {{{ proto int gmp_jacobi(mixed a, mixed b)
  1456. Computes Jacobi symbol */
  1457. ZEND_FUNCTION(gmp_jacobi)
  1458. {
  1459. gmp_binary_opl(mpz_jacobi);
  1460. }
  1461. /* }}} */
  1462. /* {{{ proto int gmp_legendre(mixed a, mixed b)
  1463. Computes Legendre symbol */
  1464. ZEND_FUNCTION(gmp_legendre)
  1465. {
  1466. gmp_binary_opl(mpz_legendre);
  1467. }
  1468. /* }}} */
  1469. /* {{{ proto int gmp_cmp(mixed a, mixed b)
  1470. Compares two numbers */
  1471. ZEND_FUNCTION(gmp_cmp)
  1472. {
  1473. zval *a_arg, *b_arg;
  1474. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){
  1475. return;
  1476. }
  1477. gmp_cmp(return_value, a_arg, b_arg TSRMLS_CC);
  1478. }
  1479. /* }}} */
  1480. /* {{{ proto int gmp_sign(mixed a)
  1481. Gets the sign of the number */
  1482. ZEND_FUNCTION(gmp_sign)
  1483. {
  1484. /* Can't use gmp_unary_opl here, because mpz_sgn is a macro */
  1485. zval *a_arg;
  1486. mpz_ptr gmpnum_a;
  1487. gmp_temp_t temp_a;
  1488. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
  1489. return;
  1490. }
  1491. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1492. RETVAL_LONG(mpz_sgn(gmpnum_a));
  1493. FREE_GMP_TEMP(temp_a);
  1494. }
  1495. /* }}} */
  1496. static void gmp_init_random(TSRMLS_D)
  1497. {
  1498. if (!GMPG(rand_initialized)) {
  1499. /* Initialize */
  1500. #if GMP_42_OR_NEWER
  1501. gmp_randinit_mt(GMPG(rand_state));
  1502. #else
  1503. gmp_randinit_lc_2exp_size(GMPG(rand_state), 32L);
  1504. #endif
  1505. /* Seed */
  1506. gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
  1507. GMPG(rand_initialized) = 1;
  1508. }
  1509. }
  1510. /* {{{ proto GMP gmp_random([int limiter])
  1511. Gets random number */
  1512. ZEND_FUNCTION(gmp_random)
  1513. {
  1514. long limiter = 20;
  1515. mpz_ptr gmpnum_result;
  1516. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &limiter) == FAILURE) {
  1517. return;
  1518. }
  1519. INIT_GMP_RETVAL(gmpnum_result);
  1520. gmp_init_random(TSRMLS_C);
  1521. #ifdef GMP_LIMB_BITS
  1522. mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS);
  1523. #else
  1524. mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB);
  1525. #endif
  1526. }
  1527. /* }}} */
  1528. /* {{{ proto GMP gmp_random_bits(int bits)
  1529. Gets a random number in the range 0 to (2 ** n) - 1 */
  1530. ZEND_FUNCTION(gmp_random_bits)
  1531. {
  1532. long bits;
  1533. mpz_ptr gmpnum_result;
  1534. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &bits) == FAILURE) {
  1535. return;
  1536. }
  1537. if (bits <= 0) {
  1538. php_error_docref(NULL TSRMLS_CC, E_WARNING, "The number of bits must be positive");
  1539. RETURN_FALSE;
  1540. }
  1541. INIT_GMP_RETVAL(gmpnum_result);
  1542. gmp_init_random(TSRMLS_C);
  1543. mpz_urandomb(gmpnum_result, GMPG(rand_state), bits);
  1544. }
  1545. /* }}} */
  1546. /* {{{ proto GMP gmp_random_range(mixed min, mixed max)
  1547. Gets a random number in the range min to max */
  1548. ZEND_FUNCTION(gmp_random_range)
  1549. {
  1550. zval *min_arg, *max_arg;
  1551. mpz_ptr gmpnum_min, gmpnum_max, gmpnum_result;
  1552. mpz_t gmpnum_range;
  1553. gmp_temp_t temp_a, temp_b;
  1554. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &min_arg, &max_arg) == FAILURE) {
  1555. return;
  1556. }
  1557. gmp_init_random(TSRMLS_C);
  1558. FETCH_GMP_ZVAL(gmpnum_max, max_arg, temp_a);
  1559. if (Z_TYPE_P(min_arg) == IS_LONG && Z_LVAL_P(min_arg) >= 0) {
  1560. if (mpz_cmp_ui(gmpnum_max, Z_LVAL_P(min_arg)) <= 0) {
  1561. FREE_GMP_TEMP(temp_a);
  1562. php_error_docref(NULL TSRMLS_CC, E_WARNING, "The minimum value must be less than the maximum value");
  1563. RETURN_FALSE;
  1564. }
  1565. INIT_GMP_RETVAL(gmpnum_result);
  1566. mpz_init(gmpnum_range);
  1567. if (Z_LVAL_P(min_arg) != 0) {
  1568. mpz_sub_ui(gmpnum_range, gmpnum_max, Z_LVAL_P(min_arg) - 1);
  1569. } else {
  1570. mpz_add_ui(gmpnum_range, gmpnum_max, 1);
  1571. }
  1572. mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range);
  1573. if (Z_LVAL_P(min_arg) != 0) {
  1574. mpz_add_ui(gmpnum_result, gmpnum_result, Z_LVAL_P(min_arg));
  1575. }
  1576. mpz_clear(gmpnum_range);
  1577. FREE_GMP_TEMP(temp_a);
  1578. } else {
  1579. FETCH_GMP_ZVAL_DEP(gmpnum_min, min_arg, temp_b, temp_a);
  1580. if (mpz_cmp(gmpnum_max, gmpnum_min) <= 0) {
  1581. FREE_GMP_TEMP(temp_b);
  1582. FREE_GMP_TEMP(temp_a);
  1583. php_error_docref(NULL TSRMLS_CC, E_WARNING, "The minimum value must be less than the maximum value");
  1584. RETURN_FALSE;
  1585. }
  1586. INIT_GMP_RETVAL(gmpnum_result);
  1587. mpz_init(gmpnum_range);
  1588. mpz_sub(gmpnum_range, gmpnum_max, gmpnum_min);
  1589. mpz_add_ui(gmpnum_range, gmpnum_range, 1);
  1590. mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range);
  1591. mpz_add(gmpnum_result, gmpnum_result, gmpnum_min);
  1592. mpz_clear(gmpnum_range);
  1593. FREE_GMP_TEMP(temp_b);
  1594. FREE_GMP_TEMP(temp_a);
  1595. }
  1596. }
  1597. /* }}} */
  1598. /* {{{ proto GMP gmp_and(mixed a, mixed b)
  1599. Calculates logical AND of a and b */
  1600. ZEND_FUNCTION(gmp_and)
  1601. {
  1602. gmp_binary_op(mpz_and);
  1603. }
  1604. /* }}} */
  1605. /* {{{ proto GMP gmp_or(mixed a, mixed b)
  1606. Calculates logical OR of a and b */
  1607. ZEND_FUNCTION(gmp_or)
  1608. {
  1609. gmp_binary_op(mpz_ior);
  1610. }
  1611. /* }}} */
  1612. /* {{{ proto GMP gmp_com(mixed a)
  1613. Calculates one's complement of a */
  1614. ZEND_FUNCTION(gmp_com)
  1615. {
  1616. gmp_unary_op(mpz_com);
  1617. }
  1618. /* }}} */
  1619. /* {{{ proto GMP gmp_nextprime(mixed a)
  1620. Finds next prime of a */
  1621. ZEND_FUNCTION(gmp_nextprime)
  1622. {
  1623. gmp_unary_op(mpz_nextprime);
  1624. }
  1625. /* }}} */
  1626. /* {{{ proto GMP gmp_xor(mixed a, mixed b)
  1627. Calculates logical exclusive OR of a and b */
  1628. ZEND_FUNCTION(gmp_xor)
  1629. {
  1630. gmp_binary_op(mpz_xor);
  1631. }
  1632. /* }}} */
  1633. /* {{{ proto void gmp_setbit(GMP a, int index[, bool set_clear])
  1634. Sets or clear bit in a */
  1635. ZEND_FUNCTION(gmp_setbit)
  1636. {
  1637. zval *a_arg;
  1638. long index;
  1639. zend_bool set = 1;
  1640. mpz_ptr gmpnum_a;
  1641. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|b", &a_arg, gmp_ce, &index, &set) == FAILURE) {
  1642. return;
  1643. }
  1644. if (index < 0) {
  1645. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
  1646. return;
  1647. }
  1648. gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
  1649. if (set) {
  1650. mpz_setbit(gmpnum_a, index);
  1651. } else {
  1652. mpz_clrbit(gmpnum_a, index);
  1653. }
  1654. }
  1655. /* }}} */
  1656. /* {{{ proto void gmp_clrbit(GMP a, int index)
  1657. Clears bit in a */
  1658. ZEND_FUNCTION(gmp_clrbit)
  1659. {
  1660. zval *a_arg;
  1661. long index;
  1662. mpz_ptr gmpnum_a;
  1663. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &a_arg, gmp_ce, &index) == FAILURE){
  1664. return;
  1665. }
  1666. if (index < 0) {
  1667. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
  1668. return;
  1669. }
  1670. gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
  1671. mpz_clrbit(gmpnum_a, index);
  1672. }
  1673. /* }}} */
  1674. /* {{{ proto bool gmp_testbit(mixed a, int index)
  1675. Tests if bit is set in a */
  1676. ZEND_FUNCTION(gmp_testbit)
  1677. {
  1678. zval *a_arg;
  1679. long index;
  1680. mpz_ptr gmpnum_a;
  1681. gmp_temp_t temp_a;
  1682. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &index) == FAILURE){
  1683. return;
  1684. }
  1685. if (index < 0) {
  1686. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
  1687. RETURN_FALSE;
  1688. }
  1689. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1690. RETVAL_BOOL(mpz_tstbit(gmpnum_a, index));
  1691. FREE_GMP_TEMP(temp_a);
  1692. }
  1693. /* }}} */
  1694. /* {{{ proto int gmp_popcount(mixed a)
  1695. Calculates the population count of a */
  1696. ZEND_FUNCTION(gmp_popcount)
  1697. {
  1698. gmp_unary_opl((gmp_unary_opl_t) mpz_popcount);
  1699. }
  1700. /* }}} */
  1701. /* {{{ proto int gmp_hamdist(mixed a, mixed b)
  1702. Calculates hamming distance between a and b */
  1703. ZEND_FUNCTION(gmp_hamdist)
  1704. {
  1705. gmp_binary_opl((gmp_binary_opl_t) mpz_hamdist);
  1706. }
  1707. /* }}} */
  1708. /* {{{ proto int gmp_scan0(mixed a, int start)
  1709. Finds first zero bit */
  1710. ZEND_FUNCTION(gmp_scan0)
  1711. {
  1712. zval *a_arg;
  1713. mpz_ptr gmpnum_a;
  1714. gmp_temp_t temp_a;
  1715. long start;
  1716. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &start) == FAILURE){
  1717. return;
  1718. }
  1719. if (start < 0) {
  1720. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero");
  1721. RETURN_FALSE;
  1722. }
  1723. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1724. RETVAL_LONG(mpz_scan0(gmpnum_a, start));
  1725. FREE_GMP_TEMP(temp_a);
  1726. }
  1727. /* }}} */
  1728. /* {{{ proto int gmp_scan1(mixed a, int start)
  1729. Finds first non-zero bit */
  1730. ZEND_FUNCTION(gmp_scan1)
  1731. {
  1732. zval *a_arg;
  1733. mpz_ptr gmpnum_a;
  1734. gmp_temp_t temp_a;
  1735. long start;
  1736. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &start) == FAILURE){
  1737. return;
  1738. }
  1739. if (start < 0) {
  1740. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero");
  1741. RETURN_FALSE;
  1742. }
  1743. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
  1744. RETVAL_LONG(mpz_scan1(gmpnum_a, start));
  1745. FREE_GMP_TEMP(temp_a);
  1746. }
  1747. /* }}} */
  1748. #endif /* HAVE_GMP */
  1749. /*
  1750. * Local variables:
  1751. * tab-width: 4
  1752. * c-basic-offset: 4
  1753. * End:
  1754. * vim600: noet sw=4 ts=4 fdm=marker
  1755. * vim<600: noet sw=4 ts=4
  1756. */